• [深入浅出Cocoa]iOS网络编程之Socket


    [深入浅出Cocoa]iOS网络编程之Socket

    [深入浅出Cocoa]iOS网络编程之Socket

    罗朝辉 (http://www.cnblogs.com/kesalin/)

    本文遵循“署名-非商业用途-保持一致”创作公用协议

    一,iOS网络编程层次模型

    在前文《深入浅出Cocoa之Bonjour网络编程》中我介绍了如何在Mac系统下进行 Bonjour 编程,在那篇文章中也介绍过 Cocoa 中网络编程层次结构分为三层,虽然那篇演示的是 Mac 系统的例子,其实对iOS系统来说也是一样的。iOS网络编程层次结构也分为三层:

    • Cocoa层:NSURL,Bonjour,Game Kit,WebKit
    • Core Foundation层:基于 C 的 CFNetwork 和 CFNetServices
    • OS层:基于 C 的 BSD socket

    Cocoa层是最上层的基于 Objective-C 的 API,比如 URL访问,NSStream,Bonjour,GameKit等,这是大多数情况下我们常用的 API。Cocoa 层是基于 Core Foundation 实现的。

    Core Foundation层:因为直接使用 socket 需要更多的编程工作,所以苹果对 OS 层的 socket 进行简单的封装以简化编程任务。该层提供了 CFNetwork 和 CFNetServices,其中 CFNetwork 又是基于 CFStream 和 CFSocket。

    OS层:最底层的 BSD socket 提供了对网络编程最大程度的控制,但是编程工作也是最多的。因此,苹果建议我们使用 Core Foundation 及以上层的 API 进行编程。

    本文将介绍如何在 iOS 系统下使用最底层的 socket 进行编程,这和在 window 系统下使用 C/C++ 进行 socket 编程并无多大区别。

    本文源码:https://github.com/kesalin/iOSSnippet/tree/master/KSNetworkDemo

    运行效果如下:

     

    二,BSD socket API 简介

    BSD socket API 和 winsock API 接口大体差不多,下面将列出比较常用的 API:

    API接口 讲解
    int socket(int addressFamily, int type,
    int protocol)

    int close(int socketFileDescriptor)

    socket 创建并初始化 socket,返回该 socket 的文件描述符,如果描述符为 -1 表示创建失败。

    close 关闭 socket。

    通常参数 addressFamily 是 IPv4(AF_INET) 或 IPv6(AF_INET6)。type 表示 socket 的类型,通常是流stream(SOCK_STREAM) 或数据报文datagram(SOCK_DGRAM)。protocol 参数通常设置为0,以便让系统自动为选择我们合适的协议,对于 stream socket 来说会是 TCP 协议(IPPROTO_TCP),而对于 datagram来说会是 UDP 协议(IPPROTO_UDP)。

    int bind(int socketFileDescriptor,
    sockaddr *addressToBind,
    int addressStructLength) 

    将 socket 与特定主机地址与端口号绑定,成功绑定返回0,失败返回 -1。

    成功绑定之后,根据协议(TCP/UDP)的不同,我们可以对 socket 进行不同的操作:
    UDP:因为 UDP 是无连接的,绑定之后就可以利用 UDP socket 传送数据了。
    TCP:而 TCP 是需要建立端到端连接的,为了建立 TCP 连接服务器必须调用 listen(int socketFileDescriptor, int backlogSize) 来设置服务器的缓冲区队列以接收客户端的连接请求,backlogSize 表示客户端连接请求缓冲区队列的大小。当调用 listen 设置之后,服务器等待客户端请求,然后调用下面的 accept 来接受客户端的连接请求。

    int accept(int socketFileDescriptor,
    sockaddr *clientAddress, int
    clientAddressStructLength)
    

    接受客户端连接请求并将客户端的网络地址信息保存到 clientAddress 中。

    当客户端连接请求被服务器接受之后,客户端和服务器之间的链路就建立好了,两者就可以通信了。

    int connect(int socketFileDescriptor,
    sockaddr *serverAddress, int
    serverAddressLength)
    

    客户端向特定网络地址的服务器发送连接请求,连接成功返回0,失败返回 -1。

    当服务器建立好之后,客户端通过调用该接口向服务器发起建立连接请求。对于 UDP 来说,该接口是可选的,如果调用了该接口,表明设置了该 UDP socket 默认的网络地址。对 TCP socket来说这就是传说中三次握手建立连接发生的地方。

    注意:该接口调用会阻塞当前线程,直到服务器返回。

    hostent* gethostbyname(char *hostname)
    
    使用 DNS 查找特定主机名字对应的 IP 地址。如果找不到对应的 IP 地址则返回 NULL。
    int send(int socketFileDescriptor, char
    *buffer, int bufferLength, int flags)
    

    通过 socket 发送数据,发送成功返回成功发送的字节数,否则返回 -1。

    一旦连接建立好之后,就可以通过 send/receive 接口发送或接收数据了。注意调用 connect 设置了默认网络地址的 UDP socket 也可以调用该接口来接收数据。

    int receive(int socketFileDescriptor, char
    *buffer, int bufferLength, int flags)
    

     从 socket 中读取数据,读取成功返回成功读取的字节数,否则返回 -1。

    一旦连接建立好之后,就可以通过 send/receive 接口发送或接收数据了。注意调用 connect 设置了默认网络地址的 UDP socket 也可以调用该接口来发送数据。

    int sendto(int socketFileDescriptor,
    char *buffer, int bufferLength, int
    flags, sockaddr *destinationAddress, int
    destinationAddressLength)
    

    通过UDP socket 发送数据到特定的网络地址,发送成功返回成功发送的字节数,否则返回 -1。

    由于 UDP 可以向多个网络地址发送数据,所以可以指定特定网络地址,以向其发送数据。

    int recvfrom(int socketFileDescriptor,
    char *buffer, int bufferLength, int
    flags, sockaddr *fromAddress, int
    *fromAddressLength)
    

    从UDP socket 中读取数据,并保存发送者的网络地址信息,读取成功返回成功读取的字节数,否则返回 -1 。

    由于 UDP 可以接收来自多个网络地址的数据,所以需要提供额外的参数,以保存该数据的发送者身份。

     

     

     

     

     

     

     

     


     

     

    三,服务器工作流程

    有了上面的 socket API 讲解,下面来总结一下服务器的工作流程。

    1. 服务器调用 socket(...) 创建socket;
    2. 服务器调用 listen(...) 设置缓冲区;
    3. 服务器通过 accept(...)接受客户端请求建立连接;
    4. 服务器与客户端建立连接之后,就可以通过 send(...)/receive(...)向客户端发送或从客户端接收数据;
    5. 服务器调用 close 关闭 socket;

    由于 iOS 设备通常是作为客户端,因此在本文中不会用代码来演示如何建立一个iOS服务器,但可以参考前文:《深入浅出Cocoa之Bonjour网络编程》看看如何在 Mac 系统下建立桌面服务器。

    四,客户端工作流程

    由于 iOS 设备通常是作为客户端,下文将演示如何编写客户端代码。先来总结一下客户端工作流程。

    1. 客户端调用 socket(...) 创建socket;
    2. 客户端调用 connect(...) 向服务器发起连接请求以建立连接;
    3. 客户端与服务器建立连接之后,就可以通过 send(...)/receive(...)向客户端发送或从客户端接收数据;
    4. 客户端调用 close 关闭 socket;

     

    五,客户端代码示例

    下面的代码就实现了上面客户端的工作流程:

    复制代码
    - (void)loadDataFromServerWithURL:(NSURL *)url
    {
        NSString * host = [url host];
        NSNumber * port = [url port];
        
        // Create socket
        //
        int socketFileDescriptor = socket(AF_INET, SOCK_STREAM, 0);
        if (-1 == socketFileDescriptor) {
            NSLog(@"Failed to create socket.");
            return;
        }
        
        // Get IP address from host
        //
        struct hostent * remoteHostEnt = gethostbyname([host UTF8String]);
        if (NULL == remoteHostEnt) {
            close(socketFileDescriptor);
            
            [self networkFailedWithErrorMessage:@"Unable to resolve the hostname of the warehouse server."];
            return;
        }
        
        struct in_addr * remoteInAddr = (struct in_addr *)remoteHostEnt->h_addr_list[0];
        
        // Set the socket parameters
        //
        struct sockaddr_in socketParameters;
        socketParameters.sin_family = AF_INET;
        socketParameters.sin_addr = *remoteInAddr;
        socketParameters.sin_port = htons([port intValue]);
        
        // Connect the socket
        //
        int ret = connect(socketFileDescriptor, (struct sockaddr *) &socketParameters, sizeof(socketParameters));
        if (-1 == ret) {
            close(socketFileDescriptor);
            
            NSString * errorInfo = [NSString stringWithFormat:@" >> Failed to connect to %@:%@", host, port];
            [self networkFailedWithErrorMessage:errorInfo];
            return;
        }
        
        NSLog(@" >> Successfully connected to %@:%@", host, port);
    
        NSMutableData * data = [[NSMutableData alloc] init];
        BOOL waitingForData = YES;
        
        // Continually receive data until we reach the end of the data
        //
        int maxCount = 5;   // just for test.
        int i = 0;
        while (waitingForData && i < maxCount) {
            const char * buffer[1024];
            int length = sizeof(buffer);
            
            // Read a buffer's amount of data from the socket; the number of bytes read is returned
            //
            int result = recv(socketFileDescriptor, &buffer, length, 0);
            if (result > 0) {
                [data appendBytes:buffer length:result];
            }
            else {
                // if we didn't get any data, stop the receive loop
                //
                waitingForData = NO;
            }
            
            ++i;
        }
        
        // Close the socket
        //
        close(socketFileDescriptor);
        
        [self networkSucceedWithData:data];
    }
    复制代码

    前面说过,connect/recv/send 等接口都是阻塞式的,因此我们需要将这些操作放在非 UI 线程中进行。如下所示:

        NSThread * backgroundThread = [[NSThread alloc] initWithTarget:self
                                                              selector:@selector(loadDataFromServerWithURL:)
                                                                object:url];
        [backgroundThread start];

    同样,在获取到数据或者网络异常导致任务失败,我们需要更新 UI,这也要回到 UI 线程中去做这个事情。如下所示:

    复制代码
    - (void)networkFailedWithErrorMessage:(NSString *)message
    {
        // Update UI
        //
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            NSLog(@"%@", message);
    
            self.receiveTextView.text = message;
            self.connectButton.enabled = YES;
            [self.networkActivityView stopAnimating];
        }];
    }
    
    - (void)networkSucceedWithData:(NSData *)data
    {
        // Update UI
        //
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            NSString * resultsString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@" >> Received string: '%@'", resultsString);
            
            self.receiveTextView.text = resultsString;
            self.connectButton.enabled = YES;
            [self.networkActivityView stopAnimating];
        }];
    }
    复制代码

       

     
     

    Cocoa开发

     
    摘要: 在前文《深入浅出Cocoa之Bonjour网络编程》中我介绍了如何在Mac系统下进行 Bonjour 编程,在那篇文章中也介绍过 Cocoa 中网络编程层次结构分为三层,虽然那篇演示的是 Mac 系统的例子,其实对iOS系统来说也是一样的。iOS网络编程层次结构也分为三层: Cocoa层:NSURL,Bonjour,Game Kit,WebKit Core Foundation层:基于 C 的 CFNetwork 和 CFNetServices OS层:基于 C 的 BSD socket Cocoa层是最上层的基于 Objective-C 的 API,比如 URL访问,NSStream,Bonjour,GameKit等,这是大多数情况下我们常用的 API。Cocoa 层是基于 Core Foundation 实现的。 Core Foundation层:因为直接使用 socket 需要更多的编程工作,所以苹果对 OS 层的 socket 进行简单的封装以简化编程任务。该层提供了 CFNetwork 和 CFNetServices,其中 CFNetwork 又是基于阅读全文
    posted @ 2013-04-13 20:41 飘飘白云 阅读(291) | 评论 (1) 编辑
     
    摘要: iOS应用是非常注重用户体验的,不光是要求界面设计合理美观,也要求各种UI的反应相对灵敏,我相信大家对那种一拖就卡卡卡的 TableView 应用没什么好印象。还记得12306么,那个速度,相信大家都受不了。为了提高 iOS 的运行速度,下面我将抛砖引玉介绍一些我实践过的方法与工具,与大家分享,希望能得到更多的反馈和建议。阅读全文
    posted @ 2013-04-05 18:07 飘飘白云 阅读(698) | 评论 (0) 编辑
     
    摘要: Core Plot和s7Graph都是可在iOS平台下使用的开源矢量图形库,s7Graph功能相对比较简单一些,在此就不介绍了。Core Plot 功能强大很多,我们可以利用它很方便地画出复杂的曲线图、柱状图和饼图等等。下面我先来介绍如何在项目中配置使用 Core Plot 库,然后通过一个曲线图示例来演示如何使用它,最后结合示例介绍 Core Plot 的框架结构。阅读全文
    posted @ 2013-04-04 13:25 飘飘白云 阅读(701) | 评论 (0) 编辑
     
    摘要: 前面写了一篇博文讲如何在 C# 中使用 ADO 访问各种数据库,在移动开发和嵌入式领域也有一个轻量级的开源关系型数据库-sqlite。它的特点是零配置(无需服务器),单磁盘文件存储数据(就像fopen一样),平台无关性,使用起来简单又高效。这些特点让其非常适合移动开发和嵌入式领域。当然,sqlite 也因其力求简单高效,也就限制了它对并发,海量数据的处理。下面,我就再接再厉,来讲讲如何在 iOS 中使用 sqlite 库和第三方封装库 FMDB,以及介绍一个 MAC 下开源的可视化 sqlite 浏览器。 本文源码:https://github.com/kesalin/iOSSnippet/tree/master/SQLiteDemo阅读全文
    posted @ 2013-03-28 23:45 飘飘白云 阅读(989) | 评论 (0) 编辑
     
    摘要: Per-Vertex 与 Per-Pixel 两种光照的异同:两者都是基于相同的光照原理来进行光照计算的,Per-Vertex 光照计算是在顶点着色阶段进行,然后在光栅化阶段进行线性插值;而 Per-Pixel 光照计算是在片元着色阶段针对每一个像素进行。因此后者要比前者效果更好,看上去更加细致逼真,当然计算量自然也要多一些。 卡通效果是将漫反射因子分级,从而形成不连续的跳跃的漫反射效果。在本文中,是在片元着色阶段进行卡通效果处理的,它也可以在顶点着色阶段进行。 在这个系列的介绍中,只提及了一些简单的光照效果,还有很多更加逼真的光照算法或技巧没有涉及,比如菲涅尔效果或使用光照贴图。阅读全文
    posted @ 2013-01-11 20:52 飘飘白云 阅读(843) | 评论 (6) 编辑
     
    摘要: 在前文《[OpenGL ES 07-1]光照原理》中已经介绍 Opengl 中的光照原理,接下来将演示如何将这些原理用 OpenGL ES 2.0 来实现。今天的这篇文章将介绍 Per-Vertex Light 以及深度缓存,下一篇文章将介绍 Per-Pixel Light 以及卡通效果。还记得在第六篇文章的末尾留了一个小作业,用顶点缓存描绘一个立方体么 Cube?在这篇文章就会用到它。Per-Vertex Light 示例效果如下:阅读全文
    posted @ 2012-12-31 21:12 飘飘白云 阅读(655) | 评论 (0) 编辑
     
    摘要: 在前文《[OpenGL ES 05]相对空间变换及颜色》中讲到人的眼睛捕捉色彩的过程:在光照的作用下,物体表面反射不同频率的光子到人的眼睛中刺激感光细胞从而形成视觉。在那一篇文章中,演示了如何使用颜色,但没有提及光照,在接下来的文章中,我将来详细介绍光的特性,物体的材质属性,光照原理以及在 OpenGL ES 2.0中的应用示例。阅读全文
    posted @ 2012-12-29 21:15 飘飘白云 阅读(916) | 评论 (5) 编辑
     
    摘要: 在前面几篇文章里,顶点数据都是在主存中分配的内存空间,当需要进行渲染时,这些数据便通过 glDrawElements 或 glDrawArrays 从 CPU 主存中拷贝到 GPU 中去进行运算与渲染。这种做法需要频繁地在 CPU 与 GPU 之间传递数据,效率低下,因此出现了 VBO (Vertex Buffer object),即顶点缓存,它直接在 GPU 中开辟一个缓存区域来存储顶点数据,因为它是用来缓存储顶点数据,因此被称之为顶点缓存。我们只会在初始化缓冲区,以及在顶点数据有变化时才需要对该缓冲区进行写操作。使用顶点缓存能够大大较少了CPU-GPU 之间的数据拷贝开销,因此显著地提升了程序运行的效率。阅读全文
    posted @ 2012-12-20 22:32 飘飘白云 阅读(909) | 评论 (2) 编辑
     
    摘要: 前面已经花了两篇文章来讲 3D 变换,可 3D 变换实在不是区区两篇文章能讲的透的,为了尽量将这个话题讲得全面点,在这篇本来讲颜色的文章里再顺带讲讲相对空间变换这个还没有提及的话题。相对空间变换类似于为“本地”坐标到“世界”坐标的变换,就是坐标空间之间的变换。你可以想象下这样一个动作,抬起胳膊同时弯曲手臂,手臂相当于在胳膊的坐标空间中旋转,而胳膊所在空间又相当于在身体或胳膊的坐标空间中旋转。就好像空间是嵌套的,一层套一层,外层会影响里层,里层的变换是相对于外层进行的。此外,还将介绍如何在 OpenGL ES 中使用颜色以及背面剔除。 今天将演示这样一个相对运动与颜色的示例,示例运行效果如下图所示,源码在这里:点此查看阅读全文
    posted @ 2012-12-11 10:42 飘飘白云 阅读(885) | 评论 (0) 编辑
     
    摘要: 在这一篇文章中,介绍了如何通过 3D 变换来实现平移,旋转和缩放,以更好地理解前文中介绍的理论知识;同时也实现了如何通过 UIControl 来控制 OpenGL View 中的物体;此外还详细介绍了描绘图元的模式以及顶点索引模式。在文章的最后,介绍了如何使用 CADisplayLink 来实现动画效果。阅读全文
    posted @ 2012-12-07 22:10 飘飘白云 阅读(1121) | 评论 (0) 编辑
     
    摘要: 本文详细介绍 3D 相关的一些数学知识,如矩阵变换,以及 3D 空间的物体是如何映射到屏幕上去这一整个过程:模型变换,视图变换,投影变换,视口变换。阅读全文
    posted @ 2012-12-06 19:57 飘飘白云 阅读(1340) | 评论 (0) 编辑
     
    摘要: 在前文《[OpenGL ES 01]iOS上OpenGL ES之初体验》中我们学习了如何在 iOS 平台上设置OpenGL ES 环境,主要是设置 CAEAGLLayer 属性,创建 EAGLContext,已经创建 renderbuffer 和 framebuffer,并知道如何清屏。但实际上并没有真正描绘点什么。在本文中,我们将学习OpenGL ES 渲染管线,顶点着色器和片元着色器相关知识,然后使用可编程管线在屏幕上描绘一个简单三角形。 在 OpenGL ES 1.0 版本中,支持固定管线,而 OpenGL ES 2.0 版本不再支持固定管线,只支持可编程管线。什么是管线?什么又是固定管线和可编程管线?管线(pipeline)也称渲染管线,因为 OpenGL ES在进行渲染处理过程中会顺序执行一列操作,这一系列相关的处理阶段就被称为OpenGL ES 渲染管线。pipeline 来源于福特汽车生产车间的流水线作业,在OpenGL ES 渲染过程中也是一样,一个操作接着一个操作进行,就如流水线作业一样,这样的实现极大地提供了渲染的效率。整个渲染管线如下图所示:阅读全文
    posted @ 2012-11-25 22:35 飘飘白云 阅读(582) | 评论 (0) 编辑
     
    摘要: OpenGL ES 是专门为手持设备指定的 3D 规范,它是 OpenGL 的简化版,该规范由khronos.org制定,目前最新规范版本为 3.0。 OpenGL ES 可以在不同手机系统上实现,也可以在浏览器上实现(Web GL)。在这里,我将介绍如何在 iOS 上使用 OpenGL ES,我是OpenGL ES 的初学者,错误之处难免,欢迎各位指出,共同提高。阅读全文
    posted @ 2012-11-24 23:24 飘飘白云 阅读(518) | 评论 (0) 编辑
     
    摘要: KVO 并不是什么新事物,换汤不换药,它只是观察者模式在 Objective C 中的一种运用,这是 KVO 的指导思想所在。其他语言实现中也有“KVO”,如 WPF 中的 binding。而在 Objective C 中又是通过强大的 runtime 来实现自动键值观察的。本文对 KVO 的使用以及注意事项,内部实现都一一做了介绍分析,通过阅读本文可以更深入地理解 KVO。Objective 中的 KVO 虽然可以用,但却非完美,有兴趣的了解朋友请查看《KVO 的缺陷》 以及改良实现 MAKVONotificationCenter 。阅读全文
    posted @ 2012-11-17 17:24 飘飘白云 阅读(1013) | 评论 (2) 编辑
     
    摘要: 如果我们在 Objective C 中向一个对象发送它无法处理的消息,会出现什么情况呢?根据前文《深入浅出Cocoa之消息》的介绍,我们知道发送消息是通过 objc_send(id, SEL, ...) 来实现的,它会首先在对象的类对象的 cache,method list 以及父类对象的 cache, method list 中依次查找 SEL 对应的 IMP;如果没有找到且实现了动态方法决议机制就会进行决议,如果没有实现动态方法决议机制或决议失败且实现了消息转发机制就会进入消息转发流程,否则程序 crash。也就是说如果同时提供了动态方法决议和消息转发,那么动态方法决议先于消息转发,只有当动态方法决议依然无法正确决议 selector 的实现,才会尝试进行消息转发。在前文中,我并没有详细讲解动态方法决议,因此本文将详细介绍之。阅读全文
    posted @ 2012-11-14 23:33 飘飘白云 阅读(1142) | 评论 (0) 编辑
     
    摘要: iOS 游戏开发教程资源,主要是 cocos2D阅读全文
    posted @ 2012-11-10 22:49 飘飘白云 阅读(424) | 评论 (0) 编辑
     
    摘要: 这是本人在研究 Cocoa 开发过程中写过的一些文章,涵盖 runtime,class, message,多线程,core data,网络,framework,plugin等各方面,还比较成系列,所以整理出来,贴在这里,希望对大家有帮助。文章错误之处,也希望大家指正。所有文章均遵循“署名-非商业用途-保持一致”创作公用协议。阅读全文
    posted @ 2012-02-19 09:31 飘飘白云 阅读(3314) | 评论 (4) 编辑
     
    摘要: XCode 内置GDB,我们可以在命令行中使用 GDB 命令来调试我们的程序。下面将介绍一些常用的命令 po, print, info, help 等以及调试技巧。阅读全文
    posted @ 2012-01-31 16:02 飘飘白云 阅读(2690) | 评论 (0) 编辑
     
    摘要: 在前文《深入浅出Cocoa之类与对象》一文中,我已经详细介绍了ObjC中的 Class 与 Object 的概念,今天我们来如何在运行 时动态创建类。下面这个函数就是应用前面讲到的Class,MetaClass的概念,在运行时动态创建一个类。这个函数来自《Inside Mac OS X-The Objective-C Programming Language》。阅读全文
    posted @ 2012-01-30 14:02 飘飘白云 阅读(1205) | 评论 (0) 编辑
     
    摘要: 最近打算写一些ObjC中比较底层的东西,尤其是 runtime 相关的。苹果已经将 ObjC runtime 代码开源了,我们可以从:http://opensource.apple.com/source/objc4/objc4-493.9/runtime/ 浏览源代码,或点此下载源代码。 从哪里入手呢?那当然是最基本的类与对象。与C++相比,ObjC中的类与对象结构要简洁与一致得多(参考《深度探索C++对象模型》,你就知道C++中类与对象结构的复杂)。本文将详细讲解ObjC中类与对象的结构,下回将讲如何在 runtime 时操作类。阅读全文
    posted @ 2012-01-19 16:59 飘飘白云 阅读(1495) | 评论 (5) 编辑
     
    摘要: 在前文深入浅出Cocoa之消息中,我简要介绍了ObjC 中消息的基本情况,包括SEL查找,缓存以及消息转发等。在本文中,我要介绍一个很有趣的技术,Method swizzling,通过这个手法,我们可以动态修改方法的实现,从而达到修改类行为的目的。当然,还有其他办法(如 ClassPosing,Category)也可以达到这个目的。ClassPosing 是针对类级别的,是重量级的手法,Category 也差不多,比较重量级,此外 Category 还无法避免下面的递归死循环(如果你的代码出现了如下形式的递归调用,应该考虑一下你的设计,而不是使用在这里介绍的 Method Swizzling 手法,:))。阅读全文
    posted @ 2012-01-05 17:01 飘飘白云 阅读(881) | 评论 (0) 编辑
     
    摘要: Three20 是 facebook 开源的一款功能齐全又强大的库,覆盖 UI,network,JSON/XML解析等。其 github 仓库在这里:https://github.com/facebook/three20 ,这个页面也有如何在工程中添加 three20 库的介绍,不过在 Lion 版下以及 xcode 4.2 下有些许不同,英文好的同学可以参看原文。现整理如下:阅读全文
    posted @ 2011-12-31 17:26 飘飘白云 阅读(403) | 评论 (2) 编辑
     
    摘要: 使用 OCMock 进行 unit test 时,我们无法 stub 或 expect 类方法,那么又该怎样测试类方法呢?下面是一个解决办法:在测试类中的非类方法 wrap 一下类方法,然后测试 wrap 方法。阅读全文
    posted @ 2011-12-27 14:25 飘飘白云 阅读(212) | 评论 (0) 编辑
     
    摘要: XCode 内置了 OCUnit 单元测试框架,但目前最好用的测试框架应该是 GHUnit。通过 GHUnit + OCMock 组合,我们可以在 iOS 下进行较强大的单元测试功能。本文将演示如何在 XCode 4.2 下使用 OCUnit, GHUnit 和 OCMock 进行单元测试。阅读全文
    posted @ 2011-12-23 12:50 飘飘白云 阅读(2575) | 评论 (0) 编辑
     
    摘要: 搜集整理了一些有关申请开发者证书,授权,申请证书,发布应用程序方面的资料,经验证,比较准确,特此保存。 1,申请 IDP 图文教程 2,如何成为一个合格的iOS开发者 3,如何为 iTunes Connect 准备应用 4,如何使用iOS授权以及如何申请证书 5,如何联机调试以及发布程序阅读全文
    posted @ 2011-12-22 20:42 飘飘白云 阅读(278) | 评论 (0) 编辑
     
    摘要: 花了几天的时间,做了一个简陋的 Dicom viewer,这个查看器没有使用 DCMTK 库,而是自己移植了一个 Dicom 文件解析器(Thanks toAmarnath S and his greatpost.)。该Dicom 文件解析器已经开源,源代码在这里 or https://github.com/kesalin/DicomViewer。 贴几张效果图先: Dicom 文件列表阅读全文
    posted @ 2011-11-18 06:34 飘飘白云 阅读(410) | 评论 (1) 编辑
     
    摘要: DCMTK是德国 Offis 公司开发的实现 DICOM 协议的跨平台开源 C++库,在医学领域里是很有名的,它支持Windows ,Linux,Mac OS,SUN等平台。不过貌似在 iOS 平台上编译 DCMTK 的文档很少很少,折腾了好久终于编译成功了,记录下来。阅读全文
    posted @ 2011-11-10 12:41 飘飘白云 阅读(353) | 评论 (0) 编辑
     
    摘要: XCode 4 默认支持 Git 作为代码仓库,当我们新建一个仓库的时候,可以勾选创建默认仓库,只不过这个仓库是在本地的。本文介绍如何在 mac 机器上创建 Git 服务器,总体思路是:使用 gitosis 来简化创建过程,在用作服务器的机器上创建一个名为 git 的账户来创建 git 服务器,其他客户端通过 ssh 机制访问 git 服务器。阅读全文
    posted @ 2011-11-07 16:09 飘飘白云 阅读(395) | 评论 (0) 编辑
     
    摘要: 苹果Cocoa编码规范阅读全文
    posted @ 2011-11-02 16:36 飘飘白云 阅读(597) | 评论 (0) 编辑
     
    摘要: Objective C 的类方法(class method),即 static 方法,那些用 + 修饰的方法。类方法是属于类对象的,所以无需创建类的实例对象我们就可以直接使用它们。使用形式为: [ClassName classMethod]; 在这里 ClassName 代表的就是一个类对象,而不是作为一种类型。类名只有出现接收消息的表达式中才代表一个类对象,其他情况下都表示一种类型。阅读全文
    posted @ 2011-11-01 12:34 飘飘白云 阅读(176) | 评论 (0) 编辑
     
    摘要: 在前文深入浅出 Cocoa 之 Framework中讲解了 Framework,接下来讲解 plugin。如果你对 Framework 还不太熟悉的话,请阅读那篇文中,在本例中使用到了 framework,并在本文中没有详细讲述其创建和使用过程。 本文代码下载:点击这里 为什么要引入插件? 我们知道编译程序时,会连接相关 framework,通常我们所连接的框架是 Foundation 和 Application 框架。当程序启动运行时,每个被连接到的 framework 都会被加载到该程序的 objc 运行时环境中。如果我们想向正在运行的程序加载新的 framework,那该怎么办呢?答案之一就是使用 plugin 机制。cocoa 的 plugin 机制通常由 NSBundle 类来实现,而实现动态加载的功能由函数 objc_addClass 来完成。一般我们无需与 objc_addClass 这个函数打交道,我们使用 NSBundle 来完成绝大部分与 plugin 相关的工作。阅读全文
    posted @ 2011-10-28 13:35 飘飘白云 阅读(469) | 评论 (0) 编辑
     
    摘要: 扩展名 pch 表示 “precompliled header”,即预编译头文件,prefix.pch 为 XCode 工程默认生成的预编译头文件,在其中我们可以定制一些全局的宏,以方便开发。阅读全文
    posted @ 2011-10-16 20:58 飘飘白云 阅读(741) | 评论 (0) 编辑
     
    摘要: Mac OS X 扩展了 framework 的功能,让我们能够利用它来共享代码和资源。framework 在概念上有点像 Window 下的库,但是比库更加强大,通过 framework 我们可以共享所有形式的资源,如动态共享库,nib 文件,图像字符资源以及文档等。系统会在需要的时候将 framework 载入内存中,多个应用程序可以同时使用同一个 framework,而内存中的拷贝只有一份。一个 framework 同时也是一个 bundle,我们可以在 finder 里浏览其内容,也可以在代码中通过 NSBundle 访问它。利用 framework 我们可以实现动态或静态库的功能。与动态/静态库相比,framework 有如下优势: 第一,framework 能将不同类型的资源打包在一起,使之易于安装,卸载与定位; 第二,framework 能够进行版本管理,这使得 framework 能不断更新并向后兼容; 第三,在同一时间,即使有多个应用程序使用同一 framework,但在内存中只有一份 framework 只读资源的拷贝,这减少了对内存的占用阅读全文
    posted @ 2011-10-16 13:43 飘飘白云 阅读(568) | 评论 (0) 编辑
     
    摘要: 最近在研究如何在 Mac 上使用 Silverlight,在这个过程中,找到几种好玩的东西: 第一个是,CSharpPlugin,链接为:http://code.google.com/p/cocoa-sharp-dev/wiki/CSharpPlugin,这个插件很神奇,可以让我们在 XCode 中编写 C#,并在编写的C#中可以调用 Cocoa API,牛吧?可惜的是这个插件很久没有更新了,最后的更新时间为 2007年5月。 第二个是,MonoDevelop,链接为:http://monodevelop.com/,一般我们还需要安装 Moonlight 。我们可以在其中编写具有 Cocoa 界面风格的 C# 程序。这个 IDE 做得非常清爽,并在持续更新中。 第三个是, 使用 Emonic 插件在 Eclipse 上开发,下面将介绍这种方式阅读全文
    posted @ 2011-10-15 14:17 飘飘白云 阅读(111) | 评论 (0) 编辑
     
    摘要: XCode 会自动为新建的工程创建本地 Git 仓库,但是如何为已有的工程创建 Git 仓库呢?Google 到下面这篇文章,贴在下面了。 原文链接:点击这里 其中 ignore文件下载为:https://github.com/github/gitignore/blob/master/Objective-C.gitignore Creating a git repository for an existing Xcode project ∞阅读全文
    posted @ 2011-09-28 15:44 飘飘白云 阅读(167) | 评论 (0) 编辑
     
    摘要: 本文通过使用 Bonjour 实现了一个简单的服务器/客户端聊天程序,演示了 CFSocket,NSNetService/NSNetServiceBrowser, NSInStream/NSOutStream 的用法。 代码下载:点击这里 效果图如下:阅读全文
    posted @ 2011-09-15 21:42 飘飘白云 阅读(1509) | 评论 (8) 编辑
     
    摘要: NSDocument 并无 setTitle 这样设置标题的方法,但有两者途径可以设置 document 的显示名: 其一,NSDocument 有一个 displayName 的方法,该方法默认实现是显示最后与该文档关联文件的名字(不显示无后缀),如果没有文件与之关联,则显示"Untitled",我们可以修改该方法的实现,返回要显示的名称。下面的这个实现,显示其中第一个 windowController 所指 window 的 title 当作文档显示名称。阅读全文
    posted @ 2011-09-08 17:46 飘飘白云 阅读(79) | 评论 (0) 编辑
     
    摘要: 前面讲解了 Core Data 的框架,并完全手动编写代码演示了 Core Data 的运作过程。下面我们来演示如何结合 XCode 强大的可视化编辑以及 Cocoa 键值编码,绑定机制来使用 Core Data。有了上面提到的哪些利器,在这个示例中,我们无需编写 NSManagedObjectModel 代码,也无需编写 NSManagedObjectContext,工程模版在背后为我们做了这些事情。 今天要完成的这个示例,有两个 Entity:StudentEntity 与 ClassEntity,各自有一个名为 name 的 Attribute。其中 StudentEntity 通过一个名为 inClass 的 relationship 与 ClassEntity关联,而 ClassEntity 也有一个名为 students 的 relationship 与 StudentEntity 关联,这是一个一对多的关系。此外 ClassEntity 还有一个名为 monitor 的 relationship 关联到 StudentEntity,表示该班的班长。阅读全文
    posted @ 2011-09-07 16:58 飘飘白云 阅读(412) | 评论 (0) 编辑
     
    摘要: 前面讲解了 Core Data 的框架,并完全手动编写代码演示了 Core Data 的运作过程。下面我们来演示如何结合 XCode 强大的可视化编辑以及 Cocoa 键值编码,绑定机制来使用 Core Data。有了上面提到的哪些利器,在这个示例中,我们无需编写 NSManagedObjectModel 代码,也无需编写 NSManagedObjectContext,工程模版在背后为我们做了这些事情。 今天要完成的这个示例,有两个 Entity:StudentEntity 与 ClassEntity,各自有一个名为 name 的 Attribute。其中 StudentEntity 通过一个名为 inClass 的 relationship 与 ClassEntity关联,而 ClassEntity 也有一个名为 students 的 relationship 与 StudentEntity 关联,这是一个一对多的关系。此外 ClassEntity 还有一个名为 monitor 的 relationship 关联到 StudentEntity,表示该班的班长。 代码下载:阅读全文
    posted @ 2011-09-07 16:44 飘飘白云 阅读(579) | 评论 (0) 编辑
     
    摘要: 前面详细讲解了 Core Data 的框架以及设计的类,下面我们来讲解一个完全手动编写代码使用这些类的示例,这个例子来自苹果官方示例。在这个例子里面,我们打算做这样一件事情:记录程序运行记录(时间与 process id),并保存到xml文件中。我们使用 Core Data 来做这个事情。 示例代码下载:点击这里阅读全文
    posted @ 2011-09-03 23:03 飘飘白云 阅读(525) | 评论 (0) 编辑
     
    摘要: Core data 是 Cocoa 中处理数据,绑定数据的关键特性,其重要性不言而喻,但也比较复杂。Core Data 相关的类比较多,初学者往往不太容易弄懂。计划用三个教程来讲解这一部分: 框架详解:讲解 Core data 框架,运作过程,设计的类; Core data应用程序示例:通过生成一个使用 Core data 的应用程序来讲解如何 在 XCode 4 中使用 Core data。 手动创建Core data示例:不利用框架自动生成代码,完全自己编写所有的 Core data 相关代码的命令行应用程序来深入讲解 Core data的使用。 本文为第一部份:框架详解阅读全文
    posted @ 2011-09-01 14:20 飘飘白云 阅读(816) | 评论 (0) 编辑
     
    摘要: block 是 Apple 在 GCC 4.2 中扩充的新语法特性,其目的是支持多核并行编程。我们可以将 dispatch_queue 与 block 结合起来使用,方便进行多线程编程。 本文源代码下载:点击下载阅读全文
    posted @ 2011-08-26 12:03 飘飘白云 阅读(527) | 评论 (0) 编辑
     
    摘要: iOS 支持多个层次的多线程编程,层次越高的抽象程度越高,使用起来也越方便,也是苹果最推荐使用的方法。下面根据抽象层次从低到高依次列出iOS所支持的多线程编程范式: 1, Thread; 2, Cocoa operations; 3, Grand Central Dispatch (GCD) (iOS4 才开始支持) 下面简要说明这三种不同范式: Thread 是这三种范式里面相对轻量级的,但也是使用起来最负责的,你需要自己管理thread的生命周期,线程之间的同步。线程共享同一应用程序的部分内存空间,它们拥有对数据相同的访问权限。你得协调多个线程对同一数据的访问,一般做法是在访问之前加锁,这会导致一定的性能开销。在 iOS 中我们可以使用多种形式的 thread: Cocoa threads: 使用NSThread 或直接从 NSObject 的类方法 performSelectorInBackground:withObject: 来创建一个线程。如果你选择thread来实现多线程,那么 NSThread 就是官方推荐优先选用的方式。 POSIX t阅读全文
    posted @ 2011-08-18 14:12 飘飘白云 阅读(763) | 评论 (0) 编辑
     
    摘要: iOS应用程序的生命周期相比 Android 应用程序的生命周期来说,没那么简明易懂,但是也并不复杂。iOS应用程序的生命周期又根据系统是否支持多线程分为两种:不支持多线程的iOS4之前的系统以及支持多线程的iOS4及其之后的系统。阅读全文
    posted @ 2011-08-16 15:04 飘飘白云 阅读(167) | 评论 (0) 编辑
     
    摘要: 在入门级别的ObjC 教程中,我们常对从C++或Java 或其他面向对象语言转过来的程序员说,ObjC 中的方法调用(ObjC中的术语为消息)跟其他语言中的方法调用差不多,只是形式有些不同而已。本文详细深入浅出地讲解了ObjC中消息的方方面面。阅读全文
    posted @ 2011-08-15 17:44 飘飘白云 阅读(764) | 评论 (0) 编辑
     
    摘要: NSString 的 stringByAddingPercentEscapesUsingEncoding 可以对 url 参数进行编码,但是有点小问题,不会对所有需要编码的字符都编码。我们可以通过 CFStringRef 的 CFURLCreateStringByAddingPercentEscapes 函数来封装这个功能。代码如下:阅读全文
    posted @ 2011-08-11 15:21 飘飘白云 阅读(266) | 评论 (0) 编辑
     
    摘要: 前文提到将开发一个美式英语发音的 app,经过半个月的业余开发,version 1.0 终于完成。截图留念。后续将完善单元详细模块,以及语音语法知识模块。阅读全文
    posted @ 2011-08-06 21:08 飘飘白云 阅读(80) | 评论 (0) 编辑
     
    摘要: iOS 中可以通过 NSPredicate 来处理正则表达式。相关资料如下: 在 iOS 中,我们使用 NSPredicate 的字符串比较功能来进行正则表达式处理,其比较关键字为:MATCHES 下面,列举一个匹配6-15个由字母/数字组成的字符串的正则表达式,来看看 NSPredicate 的具体使用:阅读全文
    posted @ 2011-08-04 13:46 飘飘白云 阅读(1582) | 评论 (0) 编辑
     
    摘要: 最近猛补了一会子美式英语音标,音调,连读相关基础知识,收获不少。遂整理相关资料笔记之,也计划做一个这样的 app 方便学习,目前已经动工,希望自己能够坚持做下去。刚开始做,主题导航框架已经完成,秀一些简陋的界面图:阅读全文
    posted @ 2011-07-22 07:44 飘飘白云 阅读(145) | 评论 (0) 编辑
     
    摘要: 有同学在 CocoaChina 上提出这样一个问题:A viewController 中包含一个 B viewController(B 的 view 作为 A 的 view 的 subView),在横竖屏转换时,A 可以得到屏幕旋转相关的消息(如:shouldAutorotateToInterfaceOrientation),而 B 却得不到,即使 A,B 都实现了这些函数。原贴见这里:http://www.cocoachina.com/bbs/read.php?tid=40973&page=1#393765 这个问题我以前也碰到过,稍微研究了一下,其原因是 A 是在 AppDelegate 里 window 的 controller 层次体系中(比如,是 navigation push进去的等等),而 B 只是创建出来,让 A 方便使用其 view 而已,B 并没有加入这个层次体系中( B 的 parentViewController 为 nil,哪怕 B.view.superview 是 A.view)。所以 A 会跟着那个层次体系得到系统旋转相关的消息,而 B 被凉在一边,阅读全文
    posted @ 2011-07-18 23:10 飘飘白云 阅读(127) | 评论 (1) 编辑
     
    摘要: 最近在 iOS 上实现了一套自定义动画库,可以支持任何数值型变量的值的自动动画演示,并支持多种动画效果,效果还是很炫的。比如说你设置了一个偏移变量从50变到100,那么这个变化过程就可以以动画形式进行,而不是常规的一步到位。与 iOS 系统自带的 Animation 相比,我的这套自定义动画库,可配置性更高,使用更简单。用 set 表示有动画的设定值,用 update 表示常规的没有动画的设定值。目前支持的动画类型如下:阅读全文
    posted @ 2011-07-17 21:25 飘飘白云 阅读(138) | 评论 (1) 编辑
     
    摘要: 自定义TableViewCell实现圆角/渐变色TableView:代码实现定制 TableViewCell,用自绘画 cell 的边角,渐变色和阴影,详细实现请下载代码:代码下载:点击这里阅读全文
    posted @ 2011-07-15 07:19 飘飘白云 阅读(336) | 评论 (0) 编辑
     
    摘要: 向 Appstore 里查询已发布App的版本信息,有两种方案,思路都是一样的: 其一:在某个服务器上存储最新发布的版本信息,需要的时候向该服务器查询; 其二:在需要的时候向 appstore 查询; 在这里我来介绍第二种方法:向 appstore 查询应用程序信息,包括作者,版本,app 介绍页面地址等信息。阅读全文
    posted @ 2011-07-14 15:40 飘飘白云 阅读(328) | 评论 (0) 编辑
     
    摘要: 在服务器使用的时区与用户本地时区不一致的情况下,如果需要显示从服务器得来的时间,我们需要进行必要的时区和显示格式转换。 其转换过程为: 获取源(服务器)NSDateFormatter,用这 NSDateFormatter 得 dateFromString 方法获得源时区的时间。 然后计算两个时区的时间偏差量,用这个偏差量加上前面计算得到的源时区时间就得到用户本地时区的时间了。阅读全文
    posted @ 2011-05-27 14:57 飘飘白云 阅读(190) | 评论 (1) 编辑
     
    摘要: XCode 3.2 常用快捷键阅读全文
    posted @ 2011-03-19 21:15 飘飘白云 阅读(118) | 评论 (0) 编辑
    分类: Cocoa开发
    标签: iosnetwork
  • 相关阅读:
    Hihocoder #1014 : Trie树
    Codevs 1298 凸包周长
    洛谷 P1355 神秘大三角(计算几何基础)
    Cogs 1688. [ZJOI2008]树的统计Count(树链剖分+线段树||LCT)
    Poj 2887 Big String(块状数组)
    P1449 后缀表达式
    P3478 [POI2008]STA-Station
    P1533 可怜的狗狗
    P2073 送花
    P1014 Cantor表
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3020411.html
Copyright © 2020-2023  润新知