Cocoa Programming学习总结

  1. OC的对象消息机制
    书中讲到,NSObject类中有一个成员变量isa,其指向一个结构体,这个结构体用于表示类的结构体,称之为类结构体。结构体中包括:该类独有的数据成员的类型(注意是类型,不是数据成员的值,地址什么的),函数列表,以及一个指向父类的类结构体指针(因为OC不允许多重继承,所以一个就够了)。其中函数列表通过一个映射列表实现的,给出一个键值将得到一个函数地址如果该键值存在的话。

    而且OC里面的类函数调用,或者称之为消息传递(更为贴切一点),都将被编译器改写为一个叫objc_sendMsg(实体对象指针,函数索引值,参数列表)的函数。该函数将通过isa指针,找到类结构体中对应的函数,如果存在则调用该函数,并传递相应参数。否则,通过类结构体的父指针找到父类的类结构体,查找函数是否存在,存在则调用,否则一直向上追溯,如果最终没有找到,则抛出异常。

  2. 派生自Cocoa的类的责任。
    书中讲到,Cocoa如果要派生类的话,需要确保及遵守一下几点。
    1.为新类编写一个指派初始化函数,并在该函数中调用父类的指派初始化函数。指派初始化函数是指真正处理函数各项初始化事物的函数,其他初始化函数一般都是调用指派初始化函数来完成初始化。所以一般指派初始化函数接受的参数最多,而其他的初始化函数一般都是为了方便用户调用便利函数。
    2.为新类重写父类的指派初始化函数,因为指派初始化都与每个类来说都很重要。如果子类没有重写父类的指派初始化函数,那么子类对象存在直接调用父类指派初始化函数的可能,如果那样的话,子类的重要数据成员就没有完成初始化,很容易造成错误。比父类更往上的类,我们将不在重写其指派初始化函数,因为用于直接调用概率比较小,如果真的调用的,那么后果不确定。所以这个地方我觉得也是OC略带瑕疵的地方。
  3. 对象创建销毁机制
    1.OC对象在被销毁之后,会调用-(void)dealloc函数。如果派生类想在自己被销毁的时候,能够清楚一些自己申请的内存或者释放持有的某个对象时,就可以通过重载-(void)dealloc函数。dealloc函数必须先清理自己的垃圾,然后才能,也必须调用父类的dealloc函数,因为父类可能在自己dealloc函数中有自己的重要操作。

    2.在调用alloc,new,copy,mutablecopy等创建函数时,对象中的引用计数为1.调用release会使对象引用计数减一,该函数会判断,当引用计数为0时调用dealloc函数销毁。autoRelease操作不会修改任何引用计数,而是将对象放入自动销毁池中,该池在某种条件下(界面程序一般是在一个消息事件出里完成后就调用一次,游戏程序一般是每帧调用一次),将为池中所有对象调用release函数,使其引用计数为0,继而被销毁。所以一般我们创建完一个对象之后,如果调用了autoRelease,那么如果你对其感兴趣,需要额外再调用一次retain,以使其引用计数为2,以使其不会被自动销毁池销毁(因为自动销毁池调用release之后对象引用计数为1,所以不会被销毁)。

    OC中有两个垃圾回收机制,一个就是常用的引用计数,另外一个就是新的Garbage Collector。前面一种存在计数错误而引起崩溃,以及“孤岛”(多个对象相互引用且与外部不相连接)问题。后者更为健全,GC模式将会通过类对象图去查找所有不能够访问的对象,这些对象就是不需要的垃圾(因为没人能访问到他),并将其清楚。这也就解决的“孤岛”问题。当然也有其弊端,就是需要花费一定的时间去遍历对象图。而且在GC模式中,所有的retain/release操作将相当于void。当一个对象不再使用时,通过将对象指针置为nil,来实现连接断开,以使GC能发现该对象不在类使用而正常清除。一般我们选择引用计数模式。

  4. accessor method
    对于类对象指针成员变量的accesstor函数,我们可以有多个编写方式。
    1.
    - (void)setFoo:(NSCalendarDate *)x
    {
        [x retain];
        [foo release];
        foo = x;
    }

    2.

    - (void)setFoo:(NSCalendarDate *)x
    {
        if (foo != x) {
          [foo release];
          foo = [x retain];
        }
    }

    3.

    - (void)setFoo:(NSCalendarDate *)x
    {
        [foo autorelease];
        foo = [x retain];
    }

    其中,我们需要注意,一般都是调用retain之后,才调用release。你可能会认为,在情况1中无所谓,因为两个对象,谁先调用无所谓,对象不会在一个函数执行过程中销毁。但是情况1中存在特例,那就是当x指针就是本身的时候,那么你先调用release,对象就可能就会被销毁,此时再调用retain,立马掉入万丈深渊。

  5. OC中的respondsToSelector:(SEL)aSelector
    我们可以通过此函数来查看一个类实例是否重写了某个SEL。常用于Delegate的接口判断。当我们制定一个Delegate之后,这个Delegate不必重写所有的接口。因为在调用Delegate的接口时,都会调用respondsToSelector来确保Delegate重写了该函数。且respondsToSelector会将结果缓存起来,以避免每次调用的遍历过程开销。
  6. key-value coding
    由于OC语言的实现机制,使得OC的多态是运行时级别的,比C++更灵活(当然也有效率代价)。通过valueForKey:,mutableArrayValueForKey等接口,可以通过变量名称获取变量指针。这些接口是通过访问对应变量的accessor方法来获取指针。通过accessor方法改变变量,会产生变量更改的消息,所有监听此变量的对象都会被通知。
    而且mutableArrayValueForKey:的灵活性更近一步,在获取arr指针之后,我们调用arr方法时,OC会去查询arr所在对象的相应函数。如
    id arrayProxy = [playlist mutableArrayValueForKey:@"songs"];
    int songCount = [arrayProxy count];

    上面代码,在[arrayProxy count]执行时,先去调用[playlist countOfSongs]。确实很令人震惊,为什么这么做,这是为了给其包含对象(playlist)一个可以改写子对象的机会吧。由于刚接触cocoa,上述代码我测试未能成功。但是下列代码测试成功了(是通过《Cocoa Programming for Mac OS 3rd》第九章的例子测试成功的)。

    [arrayProxy insertObject:p atIndex:4] // is the same as
    [playlist insertObject:p inSongsAtIndex:4]; // if the method exists
    [arrayProxy removeObjectAtIndex:3] // is the same as
    [playlist removeObjectFromSongsAtIndex:3] // if the method exists
  7. -(void)forwardInvocation:(NSInvocation*)x
    当一个对象被发送了一个它不明白的消息的时候(即它没有这个函数),OC会查看这个对象是否重写了-(void)forwardInvocation:(NSInvocation*)x函数,如果重写了,则OC就调用该函数,如果未重写则报出异常。这样我们可以看到,一个未知消息的集中处理站点就是-(void)forwardInvocation:(NSInvocation*)x。好好利用它,可以带来一想不到的好处。

    如NSUndoManager就重写了这个函数。我们可以在NSUndoManager中添加一个undo操作函数。一旦点击Undo,这个函数会被执行。NSUndoManager没有单独写一个接口去接受对象,函数地址,参数(以方便以后调用undo操作函数),而是利用forwardInvocation:(NSInvocation*)x中的x,直接传递的undo操作函数(即x,NSInvocation就是对象,函数地址,参数的封装对象)加入到undo堆栈中。所以我们往NSUndoManager中添加Undo操作函数的方法是:

    [[[self undoManager] prepareWithInvocationTarget:self] removeObjectFromEmployeesAtIndex:index];

    上面语句就像[self removeObjectFromEmployeesAtIndex:index]函数调用,传递给了undoManager。

  8. Cocoa对象的Delegate将自动称为Cocoa对象的监听者
    当一个对象(A)是一个Cocoa对象(称为B,记住一定要是Cocoa对象)的delegate,那么当B调用postNotification发送通知消息(C)的时候,会查询其delegate(即A)是否有相应的处理函数(D),如果存在则调用。其中Cocoa对象发送的通知消息(C)和delegate的处理函数(D)存在如下对应关系:

    NSWindowDidResizeNotification——>windowDidResize:(NSNotification*)notification

    从上面我们可以看出来转换规则,即将通知消息的NS前缀和Notification后缀去掉,将剩下的字符串首字母小写作为delegate的处理函数。

时间: 2024-10-26 05:43:59

Cocoa Programming学习总结的相关文章

Cocoa编程学习笔记之MVC

Cocoa 使用了一种修改版本的MVC模式来处理GUI的显示.MVC模式(自1979年以来)已经出现很长时间了,它皆在分离显示用户界面所需的大量任务,并处理用户交互.正如名称所蕴含的,MVC具有三个主要部分,Model(模型).View(视图)和Controller(控制器): 模型--模型是特定于领域的数据表现形式.比如说,我们正在创建一个任务列表应用程序.你可能会有一个Task对象的集合,书写为List. 你或许把这些数据保存在数据库.XML文件,或者甚至从Web Service中得到,不过

[翻译] 如何学习Cocoa

[文章原地址]http://funwithobjc.tumblr.com/个人翻译,难免会有错误,请各位看官海涵,翻译在末尾本人将在文章的部分地方添加注释,并根据需求增减文章内容,在此对原作者辛勤劳作表示感谢  How to learn Cocoa This is something any experienced Cocoa developer has been asked at least half a dozen times: "What's the best way to learn O

《Mac OS X 背后的故事》读后记

         <Mac OS X 背后 的故事>介绍了mac系统的由来和故事性的过程,包括mac的内核变迁.芯片适配.文件系统.多核支持.64/32支持等等,介绍了mac操作系统是怎样炼成的.           就像技术史一样,可以了解到很多操作系统底层库以及其他涉猎:        <Cocoa Programming Developer's Handbook>          GCD与多核并发编程问题          LLVM          GDB        

《从零开始学Swift》学习笔记(Day 63)——Cocoa Touch设计模式及应用之单例模式

原创文章,欢迎转载.转载请注明:关东升的博客   什么是设计模式.设计模式是在特定场景下对特定问题的解决方案,这些解决方案是经过反复论证和测试总结出来的.实际上,除了软件设计,设计模式也被广泛应用于其他领域,比如UI设计和建筑设计等. 下面来介绍Cocoa Touch框架中的设计模式中的单例模式.   单例模式 单例模式的作用是解决"应用中只有一个实例"的一类问题.在Cocoa Touch框架中,有UIApplication.NSUserDefaults和NSNotificationC

《从零开始学Swift》学习笔记(Day67)——Cocoa Touch设计模式及应用之MVC模式

原创文章,欢迎转载.转载请注明:关东升的博客   MVC(Model-View-Controller,模型-视图-控制器)模式是相当古老的设计模式之一,它最早出现在Smalltalk语言中.现在,很多计算机语言和架构都采用了MVC模式.   MVC模式概述 MVC模式是一种复合设计模式,由 "观察者"(Observer)模式."策略"(Strategy)模式和"合成"(Composite)模式等组成.MVC模式由3个部分组成,如图所示,这3个部分

《从零开始学Swift》学习笔记(Day 65)——Cocoa Touch设计模式及应用之选择器

原创文章,欢迎转载.转载请注明:关东升的博客   实现目标与动作关联使用UIControl类addTarget(_:action:forControlEvents:)方法,示例代码如下: button.addTarget(self, action: "onClick:", forControlEvents: UIControlEvents.TouchUpInside) 其中的action参数"onClick:"事实上就是选择器(Selector).   问题提出 任

《从零开始学Swift》学习笔记(Day 52)——Cocoa错误处理模式

原创文章,欢迎转载.转载请注明:关东升的博客   Swift错误处理模式,在Swift1.x和Swift 2.0是不同的两种模式. Swift 1.x代码错误处理模式采用Cocoa框架错误处理模式,到现在Objective-C还沿用这种处理模式,而Swift2.0之后采用了do-try-catch错误处理模式. 下面的示例代码是从文件中读取字符串到内存中,如果使用Swift 1.x错误处理模式代码如下: import Foundation var err: NSError? //定义可选的NSE

《从零开始学Swift》学习笔记(Day 68)——Cocoa Touch设计模式及应用之响应者链与触摸事件

原创文章,欢迎转载.转载请注明:关东升的博客  应用与用户进行交互,依赖于各种各样的事件.事件响应者对象是可以响应事件并对其进行处理的对象,响应者链是由一系列链接在一起的响应者组成的.响应者链在事件处理中是非常重要的,响应者链可以把用户事件路由给正确的对象.   响应者对象与响应链 UIResponder是所有响应者对象的基类,它不仅为事件处理,而且也为常见的响应者行为定义编程接口.UIApplication.UIView(及其子类,包括UIWindow)和UIViewController(及其

《从零开始学Swift》学习笔记(Day 66)——Cocoa Touch设计模式及应用之通知机制

原创文章,欢迎转载.转载请注明:关东升的博客   通知(Notification)机制是基于观察者(Observer)模式也叫发布/订阅(Publish/Subscribe)模式,是 MVC( 模型-视图-控制器)模式的重要组成部分.   问题提出 天气一直是英国人喜欢讨论的话题,而最近几年天气的变化也成为中国人非常关注的话题.我会根据天气预报决定是坐地铁还是开车上班,我的女儿也会根据天气预报决定明天穿哪件衣服.于是我在移动公司为我的手机定制了天气预报短信通知服务,它的工作模型如图所示.