objective-编程全解Objective C是一门为诧言增加了面向对象功能开_第1页
objective-编程全解Objective C是一门为诧言增加了面向对象功能开_第2页
objective-编程全解Objective C是一门为诧言增加了面向对象功能开_第3页
objective-编程全解Objective C是一门为诧言增加了面向对象功能开_第4页
objective-编程全解Objective C是一门为诧言增加了面向对象功能开_第5页
免费预览已结束,剩余49页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Objective-CC诧言增加了面向对象功能的诧言,是开发MacOSX、iPodtouchiPad在为C诧言加入了面向对象功能的诧言中,C++是最有名的一种。Objective-C和C++完全丌同。Objective-CJava、C#Ruby也有所丌同,是一门比Objective-C最大的特点是支持面向对象编程,具备徆多劢态诧言才有的劢态特征,同时在效率上还可以媲美C诧言。学习过其他面向对象诧言的人可能会对Objective-C为C诧言添加的功能乊少感到惊讶。MacOSXiOS的逐步更新,Objective-C运行的系统环境也做了同步升级。同时Objective-C诧言本身也引入了丌少新的特性,包括一种新的内存管理斱式——ARC。另外属性和代码块(block)的使用范围也得到了扩大。Objective-C的编程MacOSXiOS应用为目的来介绉Objective-CC诧言基础,但并丌要求精通C诧言。Objective-C和苹果公司的产品和运行环境紧密相关,介绉Objective-C的时候无中的主要类,同时也尽可能了MacOSX和iOS的丌同乊处。 GUI控件的使用,所以并丌是说读了本书就能立刻做出一个具有优美界面的应用程序。已绊有太多的优秀书籍介绉GUI编程的斱斱面面,请参考这些的内容。Xcode是苹果公司向开发人员提供的集成开发环境,用亍开发MacOSX和iOS的应用,其中自带了Objective-C的编译器。到笔者写作本书为止,Xcode可以免费安装(叧能安装在苹果系统中,没有Windows版)。而丏叧要加入苹果公司的开发者计划,成为AppleDeveloper,就可免费获取创建iOS应用和Mac应用的资源,包 戒iPad的真机上测试自己开发的应用并发布到AppleStore,则需要加入苹果公司的iOS开发者计划。本代码都是终端类型的程序,叧要安装了Xcode,丌需要对Xcode作任何Objective-CARC的斱斱面面,从工作原理AFoundationBCoreFoundationC MacOSX和iOS的软件开发环境的可扩展性非常好,也徆人性化,叧要具备基础知识就能够开发出简单的应用。但如果要开发一个真正的应用,还需要具备系统化的Objective-C知识,因为运行环境是为了最大限度地发挥Objective-C的特征而设Objective-C的基础知识乊后,你也就可以更加得心应手地使用2011年10月5日,Apple公司(NeXT公司)的缔造者逝丐。总能第1 与 与 与 第2 类的接口与 与 编 与 参考文档和 与 第3 使用self调用斱 使用super调用斱 与 第4 多 空指针 与 与 类的前置 类对 类变 第5 计 斱法和对象所与 与 常量修饰符 分数类 什么是 斱法 斱法dealloc的定 循环和弱循环 弱自劢nil化的弱 第6 回 弱自劢nil 实时 第7 属性 与 原子 第8 类 初始 选择器和SEL类 cocoa环境和 Touch和 框 与 第9 字符串类 数组 数组对象的所 枚丼器 集合 词典 包裹 关亍 第10 范 范 范 类扩 与 关联 第11 抽象 类 第12 协 协议的 与 第13 对象的及对象的浅和深区 实现可变归 属性 第14 块对 C编译器 块对象和类型 块对象的 作为Objective-C对象的块对 第15 委 通 与 反应 第16 应用 与 iOS中资源的 加载nib文 在 X中加载nib文 在iOS中加载nib文 默讣 本地 沙盒 第17 通 main函数和MyViewerCtrl 类 类 与 第18 异 异常表示类 与 日志输出函数 异常的发生和异常的 异常处理程序的断 断言 与 与 多线 373使 互 死 条件 NSOperation和NSOperationQueue的简单用 类 类 类 连 398 第20章

属 根据键路径迚行 一对多关系的 一对多关系的可变 什么是Cocoa绋 Objective-C近年来一直备受关注,它诞生于1983年,设计之初和C++一样都是为给C语 发布之前,Objective-C一直都是一门默默无闻的小众语言,而C++则长期占据编程语言榜的前几名。随着 销量的爆发性增长,Objective-C语言的份额也迅速增长。在TIOBE编程语言榜上,Objective-C只用了短短的3年时间就从2009年8月的第二十名增长到了2012年7月的第三名(仅次于C语言和Java,截至今天仍然因为Objective-C流行的时间还比较短,所以就算是开发过多个上架AppiOS程序员也仍可能不完全了解Objective-C语言。例如,不知道消息转发背后的工作机制,不了解Objective-C几种内存管理之间的区别,不清楚该如何选择Delegate、Notification和KVO等。本书是一本专门讲解Objective-C的,虽然作者并不会教你如何使用Xcode开发一个运 上的App,但用了20章的内容深入讲解了Objective-C的各个特性。2014年苹果公司在WWDC2014开发者大会上发布了用于MacOSX和iOS编程的新一代编程语言Swift,相信很多读者一定在为应该学习Objective-C还是应该直接学习Swift而感到困惑。Swift于2014年才发布,而目前市面上至少有上百万个App和类库都是用Objective-C编得Objective-C。除了讲解Objective-C语言本身外,本书还介绍了与其密不可分的Foundation框架,介绍了本书的作者荻原刚志教授从 还诞的201就始写cSX的bcieC编程门书,是eie-C方面正的专。者写这本时把人认严谨天性发挥到了致,了400页来讲解eie。本已经再版了三次,本次译的就是的第三版。作者在讲述每个知识点的时候都精心配置了示例代码,所有的示例代码均可运行。相信过本的习一能打坚的btvC础发更妙的p。Objective-C是一门为C语言增加了面向对象功能的语言,是开发MacOSX、、iPodtouch和iPad应用的主要语言。在为C语言加入了面向对象功能的语言中,C是最有名的一种。Objective-C和C完全不同。Objective-C和大家所熟知的Java、C#和Ruby也有所不同,是一门比较独特的语言。Objective-C最大的特点是支持面向对象编程,具备很多动态语言才有的动态特征,同时在效率上还可以媲美C语言。学习过其他面向对象语言的人可能会对Objective-C为C语言添加随着MacOSX和iOS的逐步更新,Objective-C运行的系统环境也做了同步升级。同时Objective-C语言本身也引入了不少新的特性,包括一种新的内存管理方式——ARC。另外属性和代码块(block)的使用范围也得到了扩大。Objective-C的编程风格这些年一直在不停地本书以开发MacOSX或iOS应用为目的来介绍Objective-C,默认读者具备C语言基础,但并不要求精通C语言。Objective-C和苹果公司的产品和运行环境紧密相关,介绍Objective-C的时候无法脱离具体的操作系统或框架。本书在介绍语言本身的同时也介绍了Foundation框架中的主要类,同时也尽可能了MacOSX和iOS的不同之处。另,书不一解cSX和 形面程书不涉及I件使用,所以并不是说读了本书就能立刻做出一个具有优美界面的应用程序。已经有太多的优秀书介绍I编的方面面请参这些的。Xcode是苹果公司向开发人员提供的集成开发环境,用于开发MacOSX和iOS的应用,其中自带了Objective-C的编译器。到笔者写作本书为止,Xcode可以免费安装(只能安装在苹果系统中,没有Windows版。而且只要加入苹果公司的开发者计划,成为AppleDeveloper,就可免费获取创建iOS应用和Mac应用的资源,包括开发工具、示例代码、技术文 或iPad的真机上测试自己开发的应用并发布到AppleStore,则需要加入苹果公司的iOS本代码都是终端类型的程序,只要安装了Xcode,不需要对Xcode作任何设置,就 序详细介绍了Objective-C新引入的内存管理方式ARC的方方面面,从工作原理到编程时的各种注意事项。以使用ARC为前提对示例程序做了大幅修改,同时简化了手动内存本书中讲解的所有内容都经过了实际编码测试。本书的代码在MacOSX10.7和iOS5以上AFoundationBCoreFoundationC编码原则 MacOSX和iOS的软件开发环境的可扩展性非常好,也很人性化,只要具备基础知识就能够开发出简单的应用。但如果要开发一个真正的应用,还需要具备系统化的Objective-C知识,因为运行环境是为了最大限度地发挥Objective-C的特征而设计的。通过本书学习了Objective-C的基础知识之后,你也就可以更加得心应手地使用其他框架了。开始享受你的Objective-C2011年10月5日,Apple公司(NeXT公司)的缔造者逝世。总能像魔第3类和 33.13.1(inhertance(superclass(subclass继承意味着子类继承了父类的所有特性,父类的数据成员和成员函数自动成为子类的数据成和成员函数。除此之外,子类还可让我们来看几个例子。在图3-1中,类BA的子类BA的实例但重写了method2。类C也是类A的子类,类C中增加了新的实例变量z和新的方法method3。类B和类C都是类A的子类,无论类A、类B和类C的任何一个实例变量都能够执行方法method1和3-1继承的概念父类和子类是一种相对的称呼。例如,在上例中,如果以B为父类又派D,那么类B相对于类A是子类,相对于类D却为父类。继承的概 类的扩展。为了避免这种命名上的,C++中把父类称为基类(baseclass),把子类称为派生类或导出类(derivedclass)。考虑到面向对象的程序设计中一般都使用父类、子类的叫法,本书也.2类的层次结假如以某个类为父类生成若干子类,然后再继承这些子类并生成的子类,如此循环下去就可能会生成一颗倒立的树,它由通过继承而彼此关联的类组成,这样的树称为类层次结构(cassheacy。3-2类层次结构的概念ClassClassClassClassClassClassClassClassClassClassClassClassClassClassClassRootNSObjectCocoa环境下的根类,Cocoa中所有的类都直接或间接地继承了NSObjectA。新建的任何类都必须是NSObject或它的继承类的子类。NSObject中定义了所有Objective-C对象的基本由于这种类的层次关系,Objective-C的所有对象都继承了NSObject类中定义的各种属性。Objective-C的对象能够作为对象来使用,就是因为类NSObject中定义了对象的基本功能在面向对象的语言中,有的和Objective-C一样有唯一根类,例如JavaSmalltalk等;有的则不存在唯一根类,如C++。A实际上,除了NSObject之外,Cocoa环境中还有一个根类NSProxy(详细内容请参考第19章 33.23.2语类定@interface类名:父类{实例变量的.}方法的.至此为止本父类都使用了NSObject,这是因为Objective-C中所有的类都要继承根类,而NSObjectObjective-C中所有类的根类。如果子类有想继承的类,就要直接指明该类为父类,否则就需要指定NSObject为父类。前文中定义Volume类的时候,因为Volume类并没有特别想继承的类,所以直接使用了NSObject作为父类。实例变量的中只需要新增的变量。如果没有新增的变量,则只需要加上{}即可,有时甚至连{}都可以省略。 下面展示了定义类AB时接口部分的情况。变量x和方法method1继承于类A,所以不需要重新,方法method2的也可以被省略。@i@interfaceB:-(voidmethod2 //这个方法被覆盖图3-1中定义类C时的接口部分如下所示,需要对变量z和方法method3进行@i@interfaceC:{i z}-(void)method3;@end利用继承定义新 假设有一个已经定义好了的类Alpha,那么头文件Alpha.h就应该已经存在。要定义类Alpha的Beta的时候,头文件Betah中必须包含Alpha.h。不知道父类定义的话是无法定义子类的。所以图3-3的文件Gammam的方法中调用了方法doSomething,这个方法是从类Alpha继承而来的。文件Gammam引入的头文件Gamma.h中引入了Betah,Betah中又引入了Alphah,所以Gamma.m可以调用方法doSomething。3-3继承和头文件的关系##import"Alpha.h...@implementationAlph...-(void)doSomething{......@e"MQIB#import"Beta.h...@implementationBet...@e#FUB#import"Gamma.h...@implementation...[selfdoSomething]...@e(BNNB(BNNB@interfaceGamma:Bet{...}...@e#import"Beta.h#FUB@interfaceBeta:Alph{...}...@e#import"Alpha.h"MQIB@e#import<Foundation/NSObject.@interfaceAlpha:NSObjec{...}-(void)doSomething .3继承和方法调如图3-4Amethod1、method2、method3。类B是类A的子类,类B中重新定义了method2。类C是类B的子类,类C中重新定义了method1。3-4继承和方法 我们来看看给类B的实例变量发送消息时的情况。首先,假设向类B的实例对象发送了对应method1的消息,即进行了方法调用。虽然类B中没有method1的定义,但因为类B的父类类A中定义了method1,所以会找到类A的method1,调用成功。消息method3的情况下也是同样的道理,类A中定义的method3会被执行。method2同前两个消息不同,类B中定义了method2,所以会使用自身定义的method2来响应这个消息。而给类C的实例发送消息的话会怎么样呢?类C中有method1的定义,所以会直接使用类C中定义的method1来响应这个消息。类C中没有method2的定义,所以调用的时候会使用类B中定义的method2来响应。类C和类B中都没有定义method3,所以类A中的定义method3会被调用。.4调用父类的方子类继承了父类之后,有时就可能会希望调用父类的方法来执行子类中定义的其他处理,或者34B的eho2的定义中调用类A的ehod,那么该怎么办呢?通过ef调用ehod2ehod2。如果子类中想调用父类的方法,可以通过super关键字来发送消息。使用super发送消息后,就会调用父类或父类的父类中定义的方法。如图3-5所示,类C中定义了method1和method3。类C的method1中通过super调用了method3,这时被调用的method3是类A中定义的method3。3-5super送消息

利用继承定义新 [supermethod3[supermethod2super和self不同,并不确定指向某个对象。所以super只能被用于调用父类的方法指定为.5定--(id)in{self=[superinit]; /*定要在第一行调用父类的init方法*/if(self!=nil){ /*返回了初始化好的实例时*/ 子类专/**}returnself}请注意第一行调用了父类的init方法,父类的init方初始化父类中定义的实例变量。下如果所有的类的初始化方法都这样写,那么根类NSObject的init方法就一定会被执行。否则执行的时候父类的初始化方法可能会出错。出错时则会返回nil,这种情况下子类也不需要再进行初始化,直接返回nil就可以了。如果父类是Nbe,则基本上不可能初始化出错,因此不判断这个返回值也是可以的。使用传入的参数或通过从文件读入变量进行初始化时,因为值的类型错误或文件失败等原因,初始sf进行了赋8章中详细说明,这里只需要记住这是初始化方法的一种固定写法即可。生成实例对象的方法alloc会把实例对象的变量都初始化为0(后面会提到的实例变量isa除外。所以,如果子类中新追加的实例变量的初值可以为0,则可以跳过子类的初始化。但是为了明 3从程序的书写角度来说,设定初始值的方法有两种,即可以在初始化方法中完成实例变量的初始化,也可以在初始化方法中先设置实例变量为默认值,然后再调用别的方法来设置实例变量oue也可以通过先调用初始化方法init,然后再调用setax等方法来设定音量的最大值、最小值和变化幅度。原则上来说,初始赋值之后值不再发生变化的变量和需要显示设.1追加新方法的例我们来定义一个带有静音功能的类MuteVolume。该类只有一个功能,即当收到mute消息时,类MuteVolume的定义非常简单,父类是已经定义Volume。子MuteVolume除了可以使用父类Volume中定义的所有实例变量和方法之外,还新增加了一个mute方法。代码3-1文件MuteVolueme.h-版本1##import"Volume.h@interfaceMuteVolume:Vol *父类是Volume*-(id)mute;@end这里使用了Volume作为父类,并引入了头文件Volumeh。Volume的父类是NSObject,所以MuteVolumeNSObject的派生类。因Volumeh中已经引入了Foundation/NSObjecth(2-2),代码3-2MuteVolume.m1#impo#import"MuteVolume.h"@implementationMuteVolume-(id)mut{val=minreturnself}代码 3-3用于测试类MuteVolume的main程

使用继承的程序示 ##import"MuteVolume.h"#import<stdio.h>intmain(void{idvcharbuf[8]v=[[MuteVolumealloc]initWithMin:0max:10step:2];while(scanf("%s",buf)>0){switch(buf[0])case'u':[vup];breakcase'd':[vdown];breakcase'm':[vmute];break;case'q':return0;}printf("Volume=%d\n",[vvalue])}return0}量。具体来说,第一个字符为u时表示提高音量,d表示降低音量,m表示静音,q表示退出程序。%%clangmain.mVolume.mMuteVolume.m-frameworkFoundati3.3.2方法重写的例假设该例子要实现两个功能。第一个功能是,当再次收到mute消息时,音量会恢复原值;第二个功能是,在静音状态下收到up或down消息时,会返回最小音量值,同时改变音量值。实现这些功能的方法有很多,这里我们增加一个BOOL类型的变量muting,同时修改方法initWithMin:max:step:和方法value的实现。码 3-4文件MuteVolume.h-版本##import"Volume.h@interfaceMuteVolume:Vol { muting} 3//*override*(id)initWithMin:(int)amax:(int)bstep:(int)s(int)value@end代码 3-5文件MuteVolume.m-版本#impo#import"MuteVolume.h"@implementationMuteVolume/*override*(id)initWithMin:(int)amax:(int)bstep:(int){self=[superinitWithMin:amax:bstep:s];if(self!=nil)muting=NO;returnself;}/*override*(int)valu{returnmuting?min:va}(id)mut{muting=!muting;returnself;}初始化方法initWithMinmaxstep:首先调用了父类的初始化方法,然后对新增value方法根据当前是否为静音状态返回不同的值。静音状态下,返回最min。mute方法中只需要改变实例变量muting的状态来标识是否静音,不需要更改音量值val。.1self调用方如果想在一个方法中调用当前类中定义的方法,可self。但如果存在继承关系,通过self继承和方法调 在图3-6的例子中,有三个类A、B、CAmethod1、method2method3三个方法。类B继承了类A,重写了method1和method3。类C继承了类B,重写了method2。[selfmethod1];[selfmethod2]假设类B的方法method3想调用method1和method2,通过self调用了method1和method2。我们来分析一下这个过到底哪个函数被调用了。对类B的实例对象调用method3方法时,首先会通过self调用method1,这个method1就是类B自身定义的method1。接着,method3通过self调用method2,因为类B中并没有method2的定义,所以就会调用从类A中继承而来的method2。而如果是类C的实例对象调用方法method3的话会怎么样呢?我们首先来看看method3,因为类C中并没有定义method3,所以调用的是类B中定义的method3。要注意这个时候selfC的实例对象,当selfmethod1]执行时,因为类C中没有定义method1,所以调用的是类B中定义的method1。然后,当selfmethod2]执行时,因为类C中定义了method2,所以执行的是类C中定义的method2,而不是上例中类A中定义的method2。另外还有一点需要注意,就算类B中定义了method2,调用的也是类C中定义的method2。也就是说,self指的是收到当前消息的实例变量,因此,就算是同一个程序,根据实例的类的不使用self的时候要一定,要仔细分辨到底调用了哪个类的方法。即便如此,利用self的特性来编程也是很常见的,详细内容请参考11.1节的内容。而如果self而使用super,程序执行的结果会怎样呢3-7是用super替代图3-6中的self的情况。使用super调用方法时,最后被调用的方法是类B的父类中定义的方法。所以无论是类B还是类C的实例变量调用了method3,最后调用到的都是类A中定义的method1和method2。 3[supermethod1];[supermethod2测试程序中有三A、B、CA中定method1method2B中对method1进行了重写,通过self调用了method1,通过super调用了method2。类C重写了method1。码 3-6文件##import<Foundation/NSObject.h>#import<stdio.h>@interfaceA:NSObjec(void)method1(void)method2;@end@implementation(void)method1{printf("method1ofClassA\n");(void)method2{printf("method2ofClassA\n");}@end@interfaceB:(void)method2;@end@implementation(void)method2printf("method2ofClassB\n");printf("self-->");[selfmethod1]printf("super-->");[supermethod2];}方法定义时的注意事 @i@interfaceC:(void)method1;@end@implementation(void)method1{printf("method1ofClassC\n");}@endintmain(void{idx=[[Balloc]init];idy=[[Calloc]init];printf("---instanceofB---\n");[xmethod1];[xmethod2]printf("---instanceofC---\n");[ymethod1];[ymethod2];return0;}程序执行之后输出如下。可以看出BC的实例分别调用了不同的方法----instanceofB---method1ofClassAmethod2ofClassBself-->method1ofClassAsuper-->method2ofClassA---instanceofC---method1ofClassCmethod2ofClassBself-->method1ofClassCsuper-->method2ofClassA.1(通常是.m文件行。这样一来,就算其他模块了接口文件,也无法获得这个方法的定义,无法调用这个方 3让我们来看一个简单的例子,类ClickVolume是类Volume的一个子类,它的主要功能是当音量发生变化(提高或降低)时发出提示音。提高或降低音量时发出提示音使用一个共同的方法playClick,定义如下所述。因为这个功能不会在其他地方使用到,所以我们把它定义成一个局@i@interfaceClickVolume:Volidup playClic法没有在这@end@implementationClickVolvoidplayClick{//类内部定义的局部方}(id)up[selfplayClick]return[superup]}(id)down[selfplayClick]return[superdown]}未在接口中的局部方法和没有进行属性的C语言函数一样,只能被定义在局部方法之后的方法调用。在上面的例子中,playClick就必须定义up和down的前面。定义顺序方面出现的问题,可以使用第10章介绍的“范畴”(category)来解决。编程的时候使用局部方法可以增强程序的可性,但在继承的时候可能会出现问题。例如,.2指定初始化方法等。(dsgadnaze就是指能确保所有实例变量都能被初始化的方法,这种方是始化,类非始方调指始化法成初化通常接参最多3.5方法定义时的注意事 子类的指定初始化方法,必须调用超类的指定初始化方法3-8中所示,按照类层次从底向上,各个类的指定初始化方被连锁调用,一直到最上层的NSObject的指定初始化方法——initᤞᤞᤞᤞᤞᤞᤞ如果子类中想重写父类中的指定初始化方法,就一定要调用父类的指定初始化方法,而不能调用父类的非指定初始化方法。原因是非指定初始化方法内部会调用指定初始化方法,造成递归循环请看图3-9中的例子,类A的指定初始化方法是initWithMax:。init是类A的非指定初始化方法。类B是类A的子类,在B中重写了指定初始化方法initWithMax:。initWithMax:中调用A的init。如图所示,如果类A的init中通过self调用了initWithMax:,那么,当初始化对象是类B的实例时,就又会调用到类B的initWithMax:,这样就变成了一个递归循环,3-9继承时重写指定初始化方法的错误 -(id)in{[selfinitWithMax:100];returnself;}-(id)initWithMax:(int)ma

-(id)initWithMax:(int)ma{[superinit];maximum=max;returnself;}{...}

再让我们回头看一下图3-8,图3-8中类的非指定初始化方法都调用了指定初始化方法来进行初ObeciveC没有特殊的语法或关键字来表明哪个方法是指定初始化方法,所以通常需要通过文档或注释来标明指定初始化方法。CocoaAPI文档中的绝大多数类都标明了哪个方法是指定初始化方法。 3202080代末, (BradCox)发明了Objective-C并创建了公司Stepstone。后来NeXTSoftware公司获得了Objective-C语言的,1996年苹果公司宣布收购NeXT公司,拥有Objective-C言的所。Objective-C身的规范是公开的,编译器也是NeXTstep司Objective-C译器是基于GUNgcc译器扩NeXTstep司又把这些扩展贡献出来,所以现在的gcc是能够编译Objective-C程序的。但是gcc和Cocoa使用不同的类库,所以本例子程序无法在gcc环境下执行。因为gcc的问题,很多开源社区把编译器由gcc为了llvm。苹果公司也为LLVM(.org/)项目提供了支援can增加了bjctie-C新功能(例如,ARC动技术等。苹果公司的Cocoa并没有开源,但OPENSTEP(Cocoa的基础)被NeXT公司开源了(OpenStep是一个开放的操作系统的规范,OPENSTEP是基于OpenStep规范的操作系统的名字,由NeXT公司开发。OpenStep在自由软件的实现叫作 )。这个项目的界面采OPENSTEP格,并提供了两个相当于MacOSXFoundationApplicationKit程序库,应用程序使Objective-CGUNStepUnixWindows也有人尝试Cocoa应用序移植到GUNStep上面专栏:Objective-C与开源第19并行NSOperation在MacOSX中使用的连接的概况。 19章并行编.1线程的基本概(had(pocsACU只有一个线程,但也可以创建多个线程并在进并行执行。应用在执行某一处理的同时,还可以接收UI除此之外,之后生成的线程称为次线程(secondarythread)或子线程(subthread。的处理,但父线程可以等到子线程执行终止后与其会合(on。而另一方面,程被创建后,也(deacNhad由于被创建的线程共享进程的地址空间,所以能够自由进程的空间变量。多线程的变量variable如果多线程胡乱共享变量,那么就不能保证变量值的正确性。所以有时就需要按照一定的规则使多线程可以协调动作。此时就必须执行线程间互斥(或者排他控制,mutualexclusion)(见19.2节使用计数管理方式时,为了使对象之间解耦合,子线程方需要创建与父线程不同的自动释.2线程安需要注C语言的函数。就现状来看,BSD函数的大部分,例如printf(等,都不是线程安多线

换、共享资源的互斥、与GUI的交互及动画显示等,在使用时都要特别。多线程便不能发挥效果,甚至还会导致未知原因的释放或异常终止。使用19.3节中介绍的而且,很多多线遇见的问题都可以通过NSTimer类或延迟消息发送(参考15.1节)来解决。19.1.419.1.4使用NSThread建线Foundation框架中提NSThread类来创建并控制线程。该类Foundation/NSThread+(void)detachNewThreadSelector:(SEL)aSelectotoTarge (id)aTargewithObjec (id)anArgumen对对象aarget调用方法创建新线程并执行。选择器aSelector必须是仅获取一个id类型参数且返回值为void(参考8.2节。使用计数管理(手动及ARC)时,有时需要执行的方法自身来管理自动释放池。此外,参数aTarget和anArgument中指定的对象也与线程同时存在,即在创建线程时被保存,程终止时使用下述的NSApplication类中的方法也能创建线程。该方法使用上面的方法,而且在使用+(void)detachDrawingThread selectotoTarge (id targewithObjec (id)argumen创建新线程并执行的方法除了上述方法还有很多,本书中不再一一介绍。其他方法请参 19章并行编以调用+(BOOL isMulti多个线程并行执行时或者只有主线执行时,只要在此之前已经创建了线程,则返回YES19.1.519.1.5当前线子线程将创建时指定的方法执行完后也会随之终止,但也可以中途终止。为此,可以使用当前(线程自身来执行下一个Nhad方法但,使用计数理时终止一定要放+(void)exi使用下述方法获得表示线程的NSThread+(NSThread*)currentThre获得表示当前线程的NSThread实例+(NSThread*)mainThre获得表示主线程的NSThread实例。查看当前线程是否为主线程时,可以使用类方法isMainThread每个线可以持有一个该线程固有的NSMutableDictionary类型的字典。向NSThread实例发-(NSMutableDictionary* threadDictionar+(void sleepForTimeInterval (NSTimeInterval +(void)sleepUntilDate:(NSDate*)aDat19.1.619.1.6GUI在使用GUI的应用中,事件处理和绘图等大部分处理中线发挥了重要作用。也可以在子线GUI应用中有较容易的方法来使用线程,即将GUI相关的时间处理或绘图集中在主线进行。使用下面的方法,就可以从子线程依赖主线的方法处理。该方法为NSOjbect的范畴,在头文件Foundation/NSThreadh中。互斥

-(void)performSelectorOnMainThread:(SEL)aSelectowithObjec (id)arwaitUntilDone:(BOOL)wa选择器aSelectr和参数arg中指定的方法的执行依赖于主线程。ait为S时,当前线程会一直等待(运行回路。19.2互斥19.2互斥19.2.1需要互斥的例例如,使用整数totalNumber来累加所处理的数据的个数。为了执行下面的加法计算,--(void)addNumber:(NSIngeger){totalNumber+=n}在OS功能支持下,线运行的过会时而得到CPU的执行权,时而被挂起执行权,2个方法的执行情况如图19-1中所示。在该图中,线程1将新计算的值保存在寄存器时挂起CPU执行权,同时线程2开始执行方法。即使CPU的执行权被挂起,寄存器的值也仍然可以被保存,所以各线能正常处理。但是,由于线程2写入的值了,因此整体上看,这偏离了我们期待的结果。19-1没有互斥的例子<<٧ߚࠃ>ĝ<٧ߚࠃ>ĝUPUBM/VNCFSĝ<٧ߚࠃ>UPUBM/VNCFSĝ<٧ߚࠃ 19章并行编在图19-1的例子中,同时只可以由一个线程占有并执行的代码部分称为临界区(critical.2锁为了使多个线程间可以相互排斥地使用全局变量等共享资源,可以使用NSLock类。该类的实例Cocoa环境中也称为锁(lock。锁和普通的实例一样,使用类方法alloc和初始化器init来创建并初始化。但是,锁应该在程NSLoNSLock*countLock=[[NSLockalloc]init](void lo如果锁正被使用,则线程进入休眠状如果锁没有被使用,则将锁的状态变为正被使用,线程继续执行(void)unlo将锁置为没有在被使用,此时如果有等待该锁资源的正在休眠的线程,则将其唤在上例中,使用锁后会产生如下效果。但需要预先创建NSLock的实例aLock。在该代码中,从某线程执行A取得锁到该线程执行B释放锁期间,其他线执行A时将进入休眠状态,不能执行临界区代码。锁被释放后,在执行A时休眠的线选择一个线程,该线取得锁后进入临界--(void)addNumber:(NSIngeger){[aLocklock];─────────────────────────────────────────totalNumber+=n //临界[aLockunlock];}某个锁被lock后,必须执行一次unlock。而且lock和unlock必须在同一个线程执行A。时theCount若想正确地自增,就需要使用锁countLock来管理。Alock和unlock必须在同一个线执行,因为NSLock是基于POSIX线程实现的 互

--(int)in{[countLocklock]++theCoun[countLockunlock];returntheCount;}--(int)in{inttmp[countLocklock];tmp=++theCoun[countLockunlock];returntmp;}各线程持有独立的栈,自动变量tmp可以在整个线局部利用,而且无需担心被其他线程访问。如果按照这样的方式执行,就可以得到临界区之后的正确值。19.2.319.2.3死锁[lockForAl[lockForAlock].../***[lockForAunlock]/[lockForBlock].../*[lockForBunlock][lockForBlock].../***[lockForBunlock]/[lockForAlock].../*[lockForAunlock] 线程1占有文件A并正在进行处理,途中又需要占有文件B。而另一方面,线程2占有着文件B,途中又需要占有文件A。大家不妨设想一下,如果线程1和线程2同时执行到了图中的箭头位置会怎么样呢?线程1为了处理文件B想要获得锁lockForB,但是它已经被线程2获得。同样,线程2想要获得的锁lockForA也被线程1占有着。这种情况下,线12就会同时进入休眠状态,而且 19章并行编预,有时则是一个线程因为自己需要获得锁而进入休眠状态。此外,由于多数情况下各个线程本身并没错处理而死锁随可发生因因就常,不排除致序bg可能。19.2.419.2.4尝试获得NSLock类不仅能获得锁和释放锁,还有检查是否能获得锁的功能。利用这些功能,就可以在不(BOOL)tryLo用尝试获得某个锁,如果可以取得该锁则返回YS。不能获得时,与lock处理不同,线程没有进入休眠状态,而是直接返回NO并继续执行。19.2.519.2.5条件锁NSConditionLock称为条件锁(conditionlock)。该锁持有整数值,根据该值可以获得锁或者(id initWithCondition (NSIntege c

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论