Tian'notes

Quick notes


  • 首页

  • 分类

  • 关于

  • 归档

  • 标签

iOS Socket通讯 - BSD Socket

发表于 2016-02-15   |   分类于 网络通讯   |  

套接字(Socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。

Socket描述了一个IP、端口对。它简化了程序员的操作,知道对方的IP以及PORT就可以给对方发送消息,再由服务器端来处理发送的这些消息。所以,Socket一定包含了通信的双发,即客户端(Client)与服务端(server)。

每一个应用或者说服务,都有一个端口。比如DNS的53端口,http的80端口。我们能由DNS请求到查询信息,是因为DNS服务器时时刻刻都在监听53端口,当收到我们的查询请求以后,就能够返回我们想要的IP信息。所以,从程序设计上来讲,应该包含以下步骤:

  1. 服务端利用Socket监听端口;

    服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。

  2. 客户端发起连接;

    指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。

  3. 服务端返回信息,建立连接,开始通信;

    当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。

总结如下:Socket是对TCP/IP协议的封装,Socket本身并不是协议,没有规定计算机应当怎么样传递消息,只是给程序员提供了一个发送消息的调用接口(API),程序员使用这个接口提供的方法,发送与接收消息。通过Socket我们才能使用TCP/IP协议。

阅读全文 »

iOS设计模式 - KVC模式

发表于 2016-02-08   |   分类于 iOS   |  

KVC(Key-value coding)键值编码,单看这个名字可能不太好理解。其实翻译一下就很简单了,就是指iOS的开发中,可以允许开发者通过Key名直接访问对象的属性,或者给对象的属性赋值。

KVC不需要调用明确的Get和Set方法。这样就可以在运行时动态在访问和修改对象的属性。而不是在编译时确定,这也是iOS开发中的黑魔法之一。

无论是Swift还是Objective-C,KVC的定义都是对NSObject的扩展来实现的,Objective-c中有个显式的NSKeyValueCoding类别名,而Swift没有,也不需要。

对于所有继承了NSObject在类型,都能使用KVC。一些纯Swift类和结构体是不支持KVC的。

下面是KVC最为重要的四个方法:

1
2
3
4
public func valueForKey(key: String) -> AnyObject? //获取键的值
public func setValue(value: AnyObject?, forKey key: String) //设置键的值
public func valueForKeyPath(keyPath: String) -> AnyObject? //获取具有路径的键的值
public func setValue(value: AnyObject?, forKeyPath keyPath: String) //设置具有路径的键的值

当然NSKeyValueCoding类别中还有其他的一些方法,下面列举一些:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class func accessInstanceVariablesDirectly() -> Bool
/**默认返回YES,表示如果没有找到Set<Key>方法的话,会按照_key,_iskey,key,iskey的顺序搜索成员,设置成NO就不这样搜索。*/
public func validateValue(ioValue: AutoreleasingUnsafeMutablePointer<AnyObject?>, forKey inKey: String) throws
/**KVC提供属性值确认的API,它可以用来检查Set的值是否正确、为不正确的值做一个替换值或者拒绝设置新值并返回错误原因。*/
public func mutableArrayValueForKey(key: String) -> NSMutableArray
/**这是集合操作的API,里面还有一系列这样的API,如果属性是一个NSMutableArray,那么可以用这个方法来返回。*/
public func valueForUndefinedKey(key: String) -> AnyObject?
/**如果Key不存在,且没有KVC无法搜索到任何和Key有关的字段或者属性,则会调用这个方法,默认是抛出异常。*/
public func setValue(value: AnyObject?, forUndefinedKey key: String)
/**和上一个方法一样,只不过是设值。*/
public func setNilValueForKey(key: String)
/**如果你在SetValue方法时将Value传nil,则会调用这个方法。*/
public func dictionaryWithValuesForKeys(keys: [String]) -> [String : AnyObject]
/**输入一组key,返回该组key对应的Value,再转成字典返回,用于将Model转到字典。*/
public func setValuesForKeysWithDictionary(keyedValues: [String : AnyObject])
/**通过这个方法直接可以将字典映射到对象。*/

上面的这些方法在碰到特殊情况或者有特殊需求还是会用到的,所以也是可以了解一下。后面的代码示例会有讲到其中的一些方法。

同时苹果对一些容器类比如NSArray或者NSSet等,KVC有着特殊的实现。建议有基础的或者英文好的开发者直接去看苹果的官方文档,相信你会对KVC的理解更上一个台阶。

阅读全文 »

iOS设计模式 - KVO原理和使用

发表于 2016-01-23   |   分类于 iOS   |  

KVO/KVC是观察者模式在Objective-C中的实现,以非正式协议(Category)的形式被定义在NSObject中。从协议的角度看,是定义了一套让开发者遵守的规范和使用的方法。

在Cocoa的MVC框架中,KVO架起ViewController和Model沟通的桥梁,例如:

代码中,在模型类A创建属性数据,在控制器中创建观察者,一旦属性数据发生改变就收到观察者收到通知,通过KVO再在控制器使用回调方法处理实现视图B的更新。

阅读全文 »

iOS案例 - GCD 死锁

发表于 2015-12-23   |   分类于 iOS   |  

首先来回忆几个概念:

  1. 任务:需要执行的操作;
  2. 队列:储存任务的数据结构;
  3. 同步:只能开启一个子线程执行队列;
  4. 异步:可开启多个子线程执行队列;
  5. 串行:同一时间只能执行一个任务;
  6. 并行:同一时间可执行多个任务;

假设你已经了解上面几个概念,那么我们开始通过几个案例来了解一下死锁:

阅读全文 »

HTTP协议 - DNS解析

发表于 2015-12-19   |   分类于 网络通讯   |  

DNS域名系统

域名系统(英文:Domain Name System,缩写:DNS)是因特网的一项服务。它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。DNS使用TCP和UDP端口53。当前,对于每一级域名长度的限制是63个字符,域名总长度则不能超过253个字符。如果要了解DNS,首先要了解一下几个概念:

根域

根域名服务器(英语:root name server)是互联网域名解析系统(DNS)中最高级别的域名服务器,负责返回顶级域名的权威域名服务器的地址。截至2014年10月,全球有504台根服务器,被编号为A到M共13个标号。编号相同的根服务器使用同一个IP,504台根服务器总共只使用13个IP。

阅读全文 »

HTTP请求 - 请求方法

发表于 2015-12-18   |   分类于 网络通讯   |  

根据HTTP标准,HTTP请求可以使用多种请求方法。

HTTP1.0定义了三种请求方法: GET, POST和HEAD方法。

HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE和CONNECT方法。

方法 描述
GET 请求指定的页面信息,并返回实体主体。
HEAD 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头。
POST 向指定资源提交数据进行处理请求,如提交表单或者上传文件。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。
PUT 从客户端向服务器传送的数据取代指定的文档的内容。
DELETE 请求服务器删除指定的页面。
CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
OPTIONS 允许客户端查看服务器的性能。
TRACE 请求服务器回显其收到的请求信息,该方法主要用于HTTP请求的测试或诊断。
阅读全文 »

HTTP协议 - HTTP请求

发表于 2015-12-17   |   分类于 网络通讯   |  

协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则,超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览。

超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)是互联网上应用最为广泛的一种网络协议。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。

阅读全文 »

iOS持久化 - NSCoding

发表于 2015-11-22   |   分类于 iOS   |  

NSCoding 是把数据存储在 iOS 和 MacOs 上的一种及其简单和方便的方式,它可以直接将一个模型对象转变成一个文件 然后再把这个文件加载到内存中,并不需要任何的文件解析和序列化的逻辑。

如果要实现利用 NSCoding 实现数据存储,首先要了解 NSoder 类和 NSCoding 协议。

NSCoder不可以直接实例化,我们需要继承 NSCoding 协议实现数据存储的功能,NSCoding 只有两个方法,从 一个是从 NSCoder 中读取数据,保存到响应的变量中,即反序列化数据,另一个是读取实例变量,并把这些数据写入到 Coder 中,即序列化输入。

1
2
3
4
5
6
7
8
9
10
class Book: NSObject, NSCoding {
required init?(coder aDecoder: NSCoder) {
print("从 Coder 中读取")
}
func encodeWithCoder(aCoder: NSCoder) {
print("保存到 Coder 中")
}
}
阅读全文 »

【转载】Swift算法 - 基本语法与技巧

发表于 2015-11-14   |   分类于 算法   |  

Swift 是苹果新推出的编程语言,也是苹果首个开源语言。相比于原来的 Objective-C,Swift 要更轻便和灵活。笔者最近使用 Swift 实践了大量的算法(绝大部分是硅谷各大公司的面试题),将心得体会总结于下。此文并不是纯粹讨论 Swift 如何实现某一个具体的算法或者数据结构,如冒泡排序、深度优先遍历,或是树和栈,而是总结归纳一些 Swift 常用的语法和技巧,以便大家在解决面试题中使用。

基本语法

1
2
3
4
5
6
7
func swap(chars:[Character], p: Int, q: Int) {
var temp = chars[p]
chars[p] = chars[q]
chars[q] = temp
}
// Assume array is a character array and it has enough elements
swap(array, p: 0, q: 1)

上面代码实现了一个非常简单的功能,就是交换一个数组中的两个值。乍一看非常正确,实际上存在以下几个问题。

  1. 在第一个参数前应该加上 inout 关键字。因为在 Swift 中,struct 都是按值传递,class 是按引用传递;数组和字典都是 struct。所以要改变原来的 chars 数组,在其前部加入 inout 关键字,表示是按引用传递。
  2. p 和 q 之前应该加入下划线。Swift 默认函数的第一个参数是局部(local)变量,而后续参数都是外部(external)变量,外部变量必须声明。如果在 p 和 q 前加上下划线,则在调用函数时无需声明外部变量,这样调用起来更简便。
  3. temp 前的 var 应该改为 let。let 用于声明常量(constant),var 用于声明变量(variable)。swap 函数中,temp 并未进行修改,所以应当视为常量,用let来声明。

除原作者以上写出的 3 点问题之外,在我编译时,也有几个方面值得记录下来:

swap 是自带的方法,API 文档描述如下:

1
2
3
4
5
/**我的笔记*/
/// Exchange the values of `a` and `b`.
///
/// - Precondition: `a` and `b` do not alias each other.
public func swap<T>(_ a: inout T, _ b: inout T)

系统提供的 swap 方法和我们自定义的方法使用略有不同,可以说更加简洁一些:

1
2
/**我的笔记*/
swap(&chars[0], &chars[1])

在我看到自定义 swap 方法时,最先想到的是在方法内部修改传入参数,需要使用 var 进行描述,而在 Swift 3 中,var 关键字被取消,强制要求我们使用 inout 关键字,当然我们也可以在方法内部创建一个新的变量:

1
2
3
4
5
6
7
8
/**我的笔记*/
func swap(chars: [String], _ p: Int, _ q: Int) -> [String] {
var chars = chars
let temp = chars[p]
chars[p] = chars[q]
chars[q] = temp
return chars
}

但这样处理是交换新的变量,而传入的 chars 是不会被修改的,因此在我们需要一份新的拷贝时,也可以使用这种方式。

阅读全文 »

iOS调试 - 单元测试

发表于 2015-10-12   |   分类于 iOS   |  

每个 iOS 程序员都要时不时的为他们的 APP 做 Debug。除非你是那种超级大牛,否则你肯定体验过查了无数个小时的 Bug 最后才发现那仅仅是个简单的语法错误时那种油然而生的绝望感。或者更糟:你根本就没发现那些 Bug。无论你是编程新手,还是开发过很多 APP 的老司机,例行的写写单元测试会让你的代码更可靠,更安全,更容易 Debug!

你很走运,Xcode 7 和 Swift 支持单元测试。尽管单元测试不保证(有了它你就会写出)绝对没有 Bug 的 APP,它还是一种能让你验证每段代码是否如期工作,并让 debug 过程更加便利。

正如其名,在单元测试中你要为某段代码单元创建一些小规模的、针对其某个特性的测试,然后确保每个代码单元都能通过这些测试。如果通过的话,它的旁边会出现一个绿色小标志,而如果因故测试不通过, Xcode 会把该测试标记为 “failed”。这就提示你去查看代码,找出失败原因。

这篇教程将简要介绍如何在 Swift 项目中使用XCTest.framework进行代码单元测试。那么我们为什么需要做单元测试呢?单元测试对于我们有以下几点帮助:

阅读全文 »
1…567…9
Tian

Tian

不积跬步,无以至千里。
不积小流,无以成江海。

83 日志
17 分类
82 标签
RSS
GitHub Weibo
© 2017 Tian
由 Hexo 强力驱动
主题 - NexT.Pisces