只有在消息表达式中才能直接用类名作为消息的接收者,而不必编写[Square class];
编译器仅仅为每个类创建一个可访问的对象叫做类对象(工厂对象),类对象负责创建属于该类的新对象。 类对象是类编译后的版本;由它创建的对象叫做类的实例。我们的程序中负责主要工作的这些对象是由类对象在运行时创建的。 一个子类可以重写所继承的方法,但是不能重写所继承的实例变量。 抽象类
抽象类是一种预先设计好让其他类继承的类。这些抽象类组织了一些方法和实例变量作为共通定义提供给子类使用。抽象类自己并不完整的定义方法(不会具体的实现方法),但是包含一些有用的代码来减少它的子类实现功能的负担。(由于抽象类必须有子类继承实现才能被使用,所以它们也被称为抽象父类。) 和其他语言不同,Objective-C不像其他语言那样会指明一个类为抽象类,也不会阻止你去实例一个抽象类。
NSObject 类就是一个很好的例子,它是Cocoa中的一个抽象类。你从来也不会在一个应用里使用到NSObject的实例那样没有任何效果,因为它只是一个普通的没有任何功能的对象。
NSView 类是抽象类的另一个例子,你有时会直接实例它并使用它。 抽象类通常包含帮助定义一个应用结构的代码。当你继承这些抽象类来创建子类,你的新类的实例可以轻松的符合应用的结构并且自动和其他对象一起工作。 类名可以出现在任何C语言所允许的类型符可以出现的地方,例如可以作为sizeof的参数:int i = sizeof(Rectangle); 静态指定类型
你可以用一个类名来代替id去定义一个对象的类型: Rectangle *myRectangle;
因为这种声明对象类型的方法明确告诉编译器了对象的类型,因此被称为静态类型。和id是一个指针一样,对象被静态指定一个类的指针作为类型。对象的类型通常都是由指针指定的。只不过静态类型是明确指向了某一个类的,而id是隐藏的。
静态指定类型允许编译器做一些类型校验。例如,如果一个指定类型的对象接收到一个无法响应的消息时(例如对象中没有消息所指定的方法)编译器会发出警告。而那些id类型的对象就没有这种限制了。同时指定静态类可以使阅读代码
的人更清楚你的意图。不过这样做并不会破坏动态绑定或改变在运行时对接收者的类进行动态确定。 类型的自查
实例在运行时可以显示出他们的类型。在NSObject 类中定义了一个isMemberOfClass: 方法,来检验接收者是否是一个特定的类型: if ([anObject isMemberOfClass:someClass]) ...
NSObject 中还定义了另一个方法isKindOfClass: 来进行更宽泛的检测,检测接收者是否继承自某一个特定的类(是否在某个类的继承体系里): if ([anObject isKindOfClass:someClass]) ...
能够使isKindOfClass: 方法返回YES的那些类就是可以把接收者静态指定的类(一系列继承关系里的类)。
类型自查并不受限于指定的类型信息。本章后面的部分会讨论返回工厂对象的方法来报告一个对象是否能够响应一个消息并且显示其他信息。
Square类是 Rectangle类的子类, Rectangle类是 Shape类的子类, Shape类是 Graphic类的子类Graphic类是 NSObject类的子类。
类对象(工厂对象)
一个类的定义包括各种信息,其中大部分是关于如何实例一个类的:
类名和它的父类
一个描述一系列实例变量的模版
声明方法名,方法返回值和方法的参数类型。 方法的实现
这些信息被编译并记录在一个数据结构体中给运行时系统使用。编译器只创建一个对象,类对象作为这个类的代表。类对象对类的所有信息都有权限访问。这些信息表述了一个类的实例是什么样的。它可以根据预先类定义的信息来创建一个新的实例。虽然一个类对象有关于这个类的实例的原型,但是它本身不是一个实例。它没有自己的实例变量并且它不能像一个实例那样执行方法。但是,类中可
以定义一种专门针对类变量的方法——类方法(相对与实例方法。)一个类对象会继承上层类的类方法,就像实例继承实例方法一样。
在源代码中类对象用类名代表。在下面的例子中,Rectangle 类使用继承自NSObject 的方法返回类版本号:
int versionNumber = [Rectangle version];
不过,类名仅在一个消息表达式中作为接收者时代表一个类对象,在别处你需要向一个类或者实例去查询并返回一个类id.
id aClass = [anObject class];id rectClass = [Rectangle class]; 通过这些例子可以看到类对象可以像其他对象一样被定义为id类型。但是类对象更多的是被定义为Class 类型:
Class aClass = [anObject class];Class rectClass = [Rectangle class];
所有类对象都是Class类型。使用class来指定一个类的类型等同于使用类型名静态指定一个实例的类型。只有实例对象可以静态的指定类型。类对象
不能这样做,因为类对象不是一个类的成员而属于Class 数据类型。
类对象是一个完整的对象,它也可以动态分配类型,接收消息,从其他类继承方法。它们唯一特殊的地方就是由编译器生成不具备类中定义的实例变量,同时他们在运行时负责创建实例对象。
注意: 编译器在生成类对象的同时还生成一个元类。它用于描述类对象,就像类对象描述类的实例一样。但是你可以向一个类实例或类对象发送消息,元类仅仅由运行时系统内部使用。 创建实例
类对象最重要的功能就是创建一个实例,下面代码就是由Rectangle 创建一个新的矩形类的实例并把他分配给myRectangle 变量:
id myRectangle;myRectangle = [Rectangle alloc];
alloc 方法动态分配内存给新对象的实例变量并且把它们初始化为0,这里面有一个例外就是isa ,这个变量负责指明新实例属于哪个类。不过一个对象通常
还需要更多更全面的初始化,这个工作是在init 方法中完成的。这个方法通常在内存分配完成后立即执行。
myRectangle = [[Rectangle alloc] init];
类似于上面的这句实例化并初始化一个实例的代码是必须的。只有初始化以后myRectangle 才能接收消息。alloc 方法返回一个新实例然后运行init 设置它的初始状态。每一个类对象至少有一个方法(例如alloc)用于创建新的对象,并且每一个实例至少有一个方法(类似init)用于初始化。初始化方法通常会接收传递的参数并用关键字标识这些参数(例如initWithPosition:size:方法就是一个新Rectangle实例的初始化方法 ),每一个初始化方法的方法名都以init开头。
每个方法调用都获得了一个名为self的隐藏参数,它是一个指向接收消息的对象的指针。方法使用self参数来查找它们要使用的实例变量。
objective-c中所有对象都是结构体,每个结构体中都有一个名为isa的指针指向其类。而类也是一种结构体,类的isa指向其父类。处于最底层的结构体是无isa的,NSObject的isa指向的也是NSObject。isa具体的值是运行时确定的。
语言特性:
1. 面向对象编程
2. Objective-C是ANSI-C的超级,可以混编C和C++代码,建立在C基础之上 3. Objective-C的最初版本并不支持垃圾回收
4. ObjC不包括命名空间机制(namespace mechanism),前缀
5. 在Cocoa编程环境中,所有Mac OS X类别和函式均有“NS”作前缀,例如NSObject或
NSButton来清楚分辨它们属于Mac OS X核心;使用“NS”是由于这些类别的名称在NeXTSTEP开发时定下。 6. 不支持运算符重载 7. 只支持单重继承
8. Categories和protocols不但可以提供很多多重继承的好处,可以避免很多错误
9. Objective-C 面向对象最大的特色是的消息传递(message passing)模型。Objective-C
里,对象不调用方法,而是互相传递消息。
10. 消息传递实现函数的间接调用,[Obj fun] 处理成 Msg_send(Obj,fun对应的id)
11. Objective-C不支持函数内联。
语法要点
1. 严格区分大小写。 2. 支持两种风格的注释。 3. 语句以分号结束。
4. #import代替#include。 import相当于C/C++中的include,但是使用import不会出
现重复包含的错误
5. 创建和释放自动回收池。
NSAutoreleasePool *Pool = [[NSAutoreleasepool alloc]init]; [pool drain];
一个线程有一个AutoreleasePool的栈式结构,可以有多个AutoreleasePool
数据类型
Objective-C的布尔类型本质是对带符号的字符类型(signed char)的定义(typedef)使用8字节的存储空间
Id :ID类型不是Objective-C的内置类型,而是用户自定义类型。
? ID类型是一种通用的指针类型。
? 对返回值和函数参数来说,id是默认类型。
Id类型是一个int类型的变量,用于区分两个不同方法
Id是通用指针类型,只要是nsobject的子类就会用id标识 Id是obje_object结构的指针 通过id找到isa成员
Nil:nil只能被应用在可以使用id类型的地方,就是Java与C++中指向对象的指针。 而NULL用于非对象指针。
nil是一个对象,而NULL只是一个值。而且我们对于nil调用方法,不会产生crash或者抛出异常
对象和类
(在Objective-C中对数据进行操作的行为,称之为方法(method),把数据称之为实例变量(instance variables)。 1. 类也是对象
2. 所有对象都在堆区分配内存,不存在在栈区实例化的对象。 3. 用指针标识实例,指针之间的赋值不会造成内容拷贝 4. 自定义类默认从NSObject继承,重用它的功能(引用计数机制,运行时类型识别机制,
内存管理机制)
5. +类方法(通过类名调用,类似于C++中的静态成员函数)和实例方法
类方法和实例方法可以同名,而且实例方法可以和实例变量同名。 6. 访问权限,访问权限修饰符如何使用
访问权限控制---实例变量的可见范围 ,实现数据隐藏 @private, @protected, @public三种。默认为@protected 访问权限修饰符后面不要加冒号。
访问权限修饰符只能用来修饰实例变量 @private
int age;
7. 类的实例化分为两步,首先分配实例所占有的内存空间,对实例的每一个实例变量进行
初始化
a) alloc是类方法,通过alloc在堆区分配实例的内存空间,返回内存空间的首地址。
b) alloc将实例变量的值默认初始化为0。
c) 调用alloc分配完内存后还需要使用init函数将实例变量初始化为有意义的值。 frac = [[Fraction alloc]init]; +alloc -init 8. 对象的生命周期,
从alloc开始到调用dealloc(间接调用)结束
alloc:类方法,功能:分配对象本身所占内存空间(类对象中得到大小);初始化引用计数为1;将实例变量的默认值设置为0;Isa成员指向类对象
Dealloc:实例方法 ,功能:回收对象本身和对象指向的实例对象内存空间
? new实际上是alloc和init的联合,由NSObject定义。
? new不是运算符,也不是原子的不可分割的,new类似于宏定义,在编译时被alloc
和init替换。
? 每个对象都有自己特有的一组实例变量
9. 属性声明,减少大量get,set方法(合成存取器方法)@property float value;
相当于自动声明了两个存取器方法。 -(float) value;
-(void) setValue:(float)aValue;
? 属性实现由关键字@synthesize完成 , @synthesize value; ? 属性声明和实现时,属性名要保持一致。
? 同种类型的属性的声明和实现可以在在一行完成,中间用逗号分隔:
10. self:调用方法的当前对象的首地址(第一个实例变量所在的位置)
self是方法的一个隐含参数, self是指向当前实例的指针。
当一个方法调用同类中的另一个方法时self不可以省略。 必须使用self指明消息的接受者。
11. [self fun]处理成Msg_Send(self,@selector(fun),varlist)
12. super是指向直接父类的指针 super:[super fun]处理成Msg_SendSuper(Superstruct
*p,Selector,varlist) 13. Struct Superstruct{
Id self;//当前对象的地址
Class superclass;//父类类对象的地址 }
14. 对象的初始化
a) 当一个对象被创建出来以后,对象的内存都被初始化为0(isa成员除外)。 b) 在有些情况下,程序需要把对象初始化为自定义状态,就应该为类提供一种可以通过传递参数进行定制初始化实例变量的方式。
c) alloc函数是基类NSObject定义的,不需要子类覆盖和修改。
15. Init方法的实现
a) 自定义初始化函数需要首先调用父类的初始化函数,初始化继承的父类的数据成员。
b) 如果父类的初始化函数执行失败,则直接返回nil, 确认父类初始化函数执行成功后,初始化本类新增的实例变量。 最后返回self给函数的调用者
参数少的初始化函数间接调用参数多的初始化函数实现代码的重用
16. 指定初始化方法
f)指定初始化方法是可以初始化每一个实例变量的方法,其它的自定义初始化方
法都通过调用指定初始化方法进行实例变量的初始化。
指定初始化方法必须先调用父类的指定初始化方法,然后再初始化本类新增加的实例变量。 -(id)initWithReal:(double)aReal andImag:(double)aImag {
if(self = [super init]) {
real = aReal; imag = aImag; }
return self; }
NSObject的指定初始化方法是init
? 初始化函数的返回类型应该是id类型。
? 自定义初始化方法应该通过调用一个指定初始化方法实现。 ? 自定义的指定初始化方法必须调用父类的指定初始化方法。 ? 应该将self作为初始化方法的返回值。 ? 应该直接通过实例变量进行赋值操作,而最好不要使用存取器方法进行赋值。
17. (参数最多的初始化方法,调用父类的指定初始化方法),参数少的初始化函数间接调
用参数多的初始化函数实现代码的重用 ,
18. 指定初始化方法是可以初始化每一个实例变量的方法,其它的自定义初始化方法都通过
调用指定初始化方法进行实例变量的初始化。
19. //明中,如果使用其他的类的指针作为函数参数,实例变量时,需要进行类型的前置声
明。@class NSColor;
20. //情况下实例方法拥有对所有本类实例变量的所有访问权,允许在一个实例方法中去调
用另外的实例方法 21.
【IT168技术】属性的定义(property)
@property (copy, nonatomic) NSString *title; 什么是assign,copy,retain之间的区别?
assign: 简单赋值,不更改索引计数(Reference Counting)。 copy: 建立一个索引计数为1的对象,然后释放旧对象
retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1 使用assign: 对基础数据类型 (NSInteger,CGFloat)和C数据类型(int, float, double, char, 等等) 使用copy: 对NSString
使用retain: 对其他NSObject和其子类
1. 内存管理有三种机制
? 垃圾回收机制(垃圾收集器,管理整个对象视图,如某对象没被其他任何对象使用,自
动释放
引用计数机制:NSObject实现 当对象被创建后,通过对象维护的一个计数器来描述有多少个其他对象在使用自己,当计数器为0时,对象将会自动调用dealloc函数,回收对象所占的内存空间。-retain方法递增当前对象引用计数。 -release方法递减引用计数。
? C语言方式。Malloc ,alloc ,free 继承
1. 公共的基类
在Objective-C中继承将几乎所有的类型连接在一起形成一个树形结构,所有的类型都有一个公共的基类。
Objective-C中,允许定义自己的根类,但通常不这样做,而是利用现有的类。 2. 继承语法
Objective-C只支持公有继承,因此并没有提供继承方式的声明方式。
@interface SubClass : NSObject ... ... @end
alloc和init是从NSObject继承来的 继承的概念作用于整个继承链
规则:先本类再父类,若在根类中也没找到则报错 3. 方法覆盖
? 规则:子类与父类的同名函数,参数的个数和类型和返回值要保持一致
? 覆盖父类的dealloc
? dealloc类似于析构函数,继承自NSObject ? 覆盖dealloc时,必须确保释放父类的内存
? release不保证释放内存,如果没有人使用当前对象才由dealloc释放内存. ? 只重写dealloc而不重写release.
? -(void) dealloc ? {
? if(origin)
? [origin release]; ? [super dealloc]; ? } 多态
不同的类共享相同名称的方法,
动态类型,程序执行时才确定对象所属的类
动态绑定能使程序直到执行时才确定要对对象调用的实际方法。
1. 只有 多态,没有静态多态
2. 来自不同的类可以定义共享相同名称的方法,方法id相同
3. Objective-C系统总是跟踪对象所属的类,类对象描述类,是对象的工厂。 4. 类对象
在Objective-C中类也是一种对象,而且在程序运行时一直存在。类对象是一种数据结构,里面存储了类的基本信息,如:类的大小,类的名称,类的版本以及消息与函数的映射表等信息。 类对象所保存的信息在程序编译时确定,在程序启动时加载到内存中(树形结构)。
@interface NSObject {
Class isa; }
@end
对象创建后对象的Isa成员指向对象所属类类对象的地址,isa成员的赋值是在alloc里面进行的 5. Id
id类型是一种通用的指针类型。 id类型可以用来指向属于任何类的对象
id实际上是objc_object结构的一个指针,里面只有一个元素那就是Class。 id就是objc_class的指针的指针。 typedef struct objc_class *Class; typedef struct objc_object { Class isa; } *id;
isa成员可以通过类对象获得当前实例可以响应的消息列表,以及和消息对
应的函数地址。
? isa成员是实例和类对象连接的桥梁。
? 类对象对于所有实例来说在内存中只保留一份副本,任何一个实例都可以通
过isa成员,访问类对象所保存的类的信息。
? isa成员可以通过类对象获得当前实例可以响应的消息列表,以及和消息对
应的函数地址。
? Objective-C系统总是跟踪对象所属的类。
对于类型的判断和方法的确定都是在运行时进行
编译时检查
Fraction *f1 = [[Fraction alloc] init]; [f1 setReal: 10.0 andImaginary: 2.5]; 运行时检查
id dataValue = [[Fraction alloc] init];
[dataValue setReal: 10.0 andImaginary: 2.5];
对象分id类型和静态类型,尽量选择静态类型
6. 如何得到类对象: 06Objc
a. 通过类名得到类对象:
Class rectClass = [Rectangle class];
b. 通过实例得到类对象:
Class aClass = [anObject class]; c. 查看时不是相同的类的实例:
if( [obj1 class] == [obj2 class]) d. 查看是否为某个类的实例
[objct isMemberOf: [someClass class]] e. 从字符串得到类对象
Class obj = ClassFromString(@”NSView”); NSView view = [[obj alloc] init];
7. Selector
Objective-C在编译的时候,会根据方法的名字,生成一个用 来区分这个方法的唯一的一个ID,这个ID就是SEL类型的。
只要方法的名字(包括参数序列)相同,那么它们的ID都是相同的。就是 说,不管是超类还是子类,不管是有没有超类和子类的关系,只要名字相同那么ID就是一样的。
8. 消息的起源
[reciver message];
编译器在处理时会将上面的表达式处理成下面这种形式: objc_msgSend(receiver, selector); //receiver是一个指针,、、、//selector是方法的id
消息流程:
? 首先通过传递的selector参数找到消息映射表中的函数。 ? 然后调用函数,将实例的地址和参数传递给调用的这个函数。 ? 最后返回返回值。
? 消息的成功传递依赖于两个重要的要素,通过实例中的isa指针找到实例所属
的类对象。
? 消息的映射表。消息名,方法id,函数地址
类类型的存在使objective-c拥有了运行时识别,动态创建,序列化等机制。
9. 分类(Category)
子类扩展:缺点,易出错,易出现紧耦合
通过继承可以实现类的扩展和代码重用 还可以通过分类实现
类的扩展:继承,分类,修改源代码
声明和实现:
@interface 类名(分类名) 方法的声明 @end
@implementation 类名(分类名) 方法的实现 @end
分类名可以不写 分类注意事项:
? 分类可以访问原始类的实例变量,但是不能为原始类添加新的实例变量,如
果确实需要添加实例变量,可以考虑创建子类。
? 分类可以覆盖原始类中的某一个方法,但是一般情况下不要这样做,覆盖一
个方法后,原有类中的方法就再也无法访问了。最佳的选择是创建子类,这样仍然可以通过super访问父类的方法。 ? 一个类可以拥有多个分类。
? 通过使用类别添加新方法扩展类不仅会影响这个类,同时也会影响它的所有
子类
? 分类既可以在单独的文件中实现,也可以与类一起实现。
10. 协议( Protocol )
声明
@protocol 协议名 //协议名是唯一的 @optional//默认 方法的声明 @required 方法的声明 @end 实现
@interface 类名:父类名 <协议名1,协议名2,...>
? confirmsToProtocol:方法检查对象是否遵守某项协议
? id
协议是多个类共享的一个方法列表。协议中列出的方法没有相
应的实现,由遵守该协议的类实现,相当于接口
? //如果currentObject未遵守Drawing协议则编译报错
? //warning:class ‘Square’ does not implement the ‘Drawing’ //protocol
? 定义协议时可以扩展现有协议的定义 11. 动态多态
Id类型可以显现动态多态,NSObject* 指针也可以实现动态多态 NSObject* p = Object; [p init]
12. 编译时检查
(1)
Franction *f1 =[[ Franction alloc] init]; [f1 setReal:10.1 andImaginary:2.5]; 编译时warnning (2)
Id<协议名> f1 = …… 编译时warnning
13. 运行时检查
id f1 =[[ Franction alloc] init];
[f1 setReal:10.1 andImaginary:2.5]; 运行时出错
14. Id类型和静态类型
Id是动态类型
静态类型可更好的在编译阶段而不是在运行时指出错误 使用静态类可读性强
15. 为什么要有id类型,不用NSObject*
因为并不是所有的类都从NSObject继承 Id类型为语言的扩展提供了可能
16. 代理delegate
a. 代理是一种组合方法,它使组合具有与继承同样的复用能力。 b. 在代理方式下,有两个对象参与处理同一个请求,接受请求的对象将操作委托给它的代理者。
。 继承:子类复用父类;代理:委托者(具体执行者),被委托者可以相互复用。
类之间关系:泛化(静态的),关联(动态的分为组合,聚 合,是对象与
对象之间的关系)
@interface Window :NSObject {
id delegate; }
-(void)setDelegate:(id)aDel; -(void)draw; @end
@implementation -(void)draw {
return [delegate Draw]; }
-(void)setDelegate:(id)aDel; {
delegate = aDel; }
@end
单向代理
而通常的代理关系,代理需要在运行时查询被代理者的状态信息 @interface Window :NSObject {
id delegate; }
-(void)setDelegate:(id)aDel; -(void)draw; @end
@implementation -(void)draw {
return [delegate Draw:self]; }
-(void)setDelegate:(id)aDel; {
delegate = aDel; }
@end
@protocol Graphic -(void)draw; @end
@interface Rectangle :NSObject {
int width; int height; }
-(void)draw @end
@implementation -(void)draw {
//rectangle draw }
@end int main() {
Window *win = [[Window alloc]init]; Rectangle *rect = [[Rectangle alloc]init]; Circle *cir = [[Circle alloc]init]; [win setDelegate: rect]; [win draw];
[win setDelegate: cir]; [win draw]; [win release]; [rect release]; [cir release]; }
? Foundation类库(
包含对象集合,如数组、字典、集合。其他功能包括内存管理、处理基础文件系统、存储对象等)Cocoa总的来说指的是Foundation和Application kit
? Cocoa Touch是Foundation和UIKit
1. 类名都是以NS-为前缀 2. 两种初始化方式
(1)InitWith……
(2)工厂方法:ArrayWith……;StringWith……;……………. Alloc,init,autoRelease 3. AutoReleasePool
向对象发送一条autorelease消息,该对象就被放到自动回收池中。(线程本地存储)
释放回收池时( [pool drain] / [pool release]时),添加到自动回收池的所有对象也
会一起被释放。(向对象发送release消息:找到和线程本地存储绑定的AutoReleasePool栈式结构,找到栈顶的AutoReleasePool,。。。)
每一个Cocoa线程都拥有一个autoreleasepool的栈,一个线程最少有一个
? 自动回收池并未包含对象本身,而是关于对象的引用 ? 由new、copy、alloc创建的对象不会自动入池,须通过发送autorelease消息,可以将一个对象添加到其中,以便以后释放:[myFraction autorelease];
? 程序中可以有多个自动释放池,并且它们可以是嵌套的
AutoReleasePool由main函数初始化??? int main() {
NSAutoReleasePool* pool =
[[NSAutoReleasePool alloc] init];
Complex *a = [[Complex alloc]initWithReal:100
andImag:100]; [a release];
Complex *b = [[Complex alloc]initWithReal:100
andImage:100];
[b autorelease];
Complex *c = [Complex valueWithReal:100
andImag:100]; [pool drain]; }
Int main() { AutoReleasePool *p = [[AP alloc] init]; NSString *p = [[] autoRelease];
AutoReleasePool *p1 = [[AP alloc] init]; }
? 以new、alloc、copy创建的对象不会添加到自动回收池,其他方法创建的对象都会
放入自动回收池
? NSInterger不是一个对象,而是基本数据类型的typedef。它代表64位或者32位的
int,用于处理程序中没有初值的整数
栈式结构的好处
4. NSNumber(用于将内置类型的数据转换为NSNumber对象)
a. 以new(alloc+init)、alloc、copy创建的对象不会添加到自动回收池,其他方
法创建的对象都会放入自动回收池
b. NSArray,NSSet…保存的必须的NSObject类型的指针,内置类型如:int,char,
自定义结构体等不能放入其中
c. NSInterger不是一个对象,而是基本数据类型的typedef。
5. NSString
#import
? 格式字符%@可以能够显示数组,字典和集合的全部内容。
? 如果通过%@格式字符来打印对象信息,程序会调用description方法返回描述对象
信息的字符串。
? NSString *str2 = @“This is string B”;(str2保留字符串在常量区地止)
6. 数组对象
保存的必须的NSObject类型的指针
Foudation数组元素的实际类型为id型
分为可变数组和不可变数组,后者是前者的子类 头文件:
NSArray *monthNames = [NSArray arrayWithObjects: @\January\, @\February\, @\March\, @\April\,
@\May\, @\June\, @\July\, @\August\, @\September\,
@\October\, @\November\, @\December\, nil ]; //必须以nil结束 NSMutableArray *primes =
[NSMutableArray arrayWithCapacity: 20]; //工厂类 // Store the first two primes (2 and 3) into the array
[primes addObject: [NSNumber numberWithInteger: 2]]; [primes addObject: [NSNumber numberWithInteger: 3]];
7. 快速枚举NSEnumerator
8. NSDictionary
? Set是一组单值对象的集合,可以是可变的,也可以是不变的。
? 操作包括:搜索,添加,删除集合的成员,比较两个集合,计算两个集合的交集和并
集等。
? NSSet *set2 = [NSSet setWithObjects:INTOBJ(-5), ? INTOBJ(100), INTOBJ(3), INTOBJ(5), nil]; ? NSSet *set3 = [NSSet setWithObjects: INTOBJ(12), ? INTOBJ(200), INTOBJ(3), nil]; 文件
? 管理文件和目录:NSFileManager ? 使用路径:NSPathUtilities.h ? 基本的文件操作:NSFileHandle
? NSData类提供了用于创建缓冲区的方法,对于32位应用程序,NSData缓冲区最多可
容纳2GB数据。对于64位应用程序,最多存储8EG(80GB数据) ? 可以定义不可变缓冲区(NSData),或者可变缓冲区(NSMutableData)
内存管理
1. 什么时候需要重写dealloc:
类中还有其他对象的指针,需要重写dealloc,先将其他对象release,再dealloc本类 Dealloc不能直接调用, 2. 引用计数
如果你的方法中不再需要一个对象,但需要返回它,那么向对象发送一条autorelease消息。autorelease消息不会影响对象的引用计数 (工厂方法)
NSMutableArray *arr = [[NSMutableArray alloc]init]; Fraction *frac = nil;
frac = [[Fraction alloc] init]; +1
[arr addObject:frac]; +1
[frac retain]; +1 [frac retain]; +1
向对象发送retainCount消息可以获得当前对象的引用次数,它返回一个NSUInterger类型的无符号整数,通常情况下,很少用这一方法 Retain方法返回对引用计数递增对象的地址 Car* car = [Car new];
[[car retain]setTire:tire atIndex: 2];
? 内存中的常量字符串的空间分配与其它对象不同,它们没有引用计数机制
3. 对象所有权
a. 一个实体拥有一个对象,那么这个实体对这个对象有所有权。强调使用的权利,使用的时候不能销毁
b. 所有权就意味着该实体确保对其拥有的对象进行清理。
c. 取得所有权的方式:
1>创建一个对象。 Copy new alloc
2>保留(retain)一个对象。 被委托与委托直接不互相拥有 int main (int argc, char *argv[]) {
NSAutoreleasePool * pool =
[[NSAutoreleasePool alloc] init]; Engine *engine = [Engine new]; [engine release]; [pool drain]; }
? main函数拥有engine对象的所有权。
无论哪种方式拥有对象,需要覆盖dealloc -(void) dealloc {
[str release]; [super dealloc]; }
4. 属性声明
修饰retain,assign(不增加引用计数) @property(assign) int value; @property(retain)NSString *str; Obj.str = str1;
Str1的引用计数递增1;Obj.str原来指向的对象的引用计数递减1;
改成:@property(copy)NSString *str;
Obj.str原来指向的对象的引用计数递减1;
给str1发送一个copy消息,返回一个副本赋值给Obj.str; NSString *p = Obj.str; 调用get函数,向Obj.str指向的对象发送copy消息,返回一个副本给p;
引用计数拥有将带来缺陷 -(void) setStr: (NSString *) s {
[str autorelease]; str = [s retain]; }
S出错则str出错
-(void) setStr: (NSString *) s{ [str release]; //组合关系 str = [NSString initWithString:s]; }
引用计数和实例变量?@property(readwrite,retain) NSString*str;?//通过设定某个接口读取,设置实例变量的值-(NSSsring*)str//read{return str;}-(NSString*)setStr:(NSString*) aStr//wirte{[aStrretain];[strrelease];str= aStr;}//去掉,则不提供某个接口ReadonlyWriteonly不生成
? @property(assign) NSString *str;
? -(NSSsring*)str ? {
? return str; ? }
? -(NSString*)setStr:(NSString*) aStr//wirte ? {
? str = aStr; ? }
不递增引用计数
自动释放池用于在释放本身时自动对池中所有对象的引用计数减1.
? 如果你的方法中不再需要一个对象,但需要返回它,那么向对象发送一条autorelease消息。autorelease消息不会影响对象的引用计数
//让其他函数或对象使用他
//当前运行的程序是一个进程,当程序结束时,将回收进程资源
? 无论对象是否添加到自动释放池,应用程序终止时都会释放程序中对象占用的所有内存
如果使用alloc和copy及new
(allocWithZone:copyWithZone:mutableCopy:)方法创建对象,则由你负责释放它
? //工厂方法,会自动被放入自动回收池
? 不了解是否在自动回收池中,可先retain,然后使用完后release
iPhone运行时环境不支持垃圾回收, 垃圾回收
? 垃圾回收的启动方式
Project->Edit Project Setting ->Gcc 4.2 Code Generation下的 Objective-C Garbage Collection
? 启动垃圾回收后,程序将忽略retain、autorelease、release和dealloc
5. Copy
a. Foundation类已经遵守了
copy和mutableCopy方法,从写copyWithzone和MutableCopyWithZone.因此Foundation对象可以使用这些方法创建对象的副本或可变副本 b. NSZone是一个C语言定义的结构体类型,用来确定内存中的一块区域。 c. Objective-C有一个默认的区域,在系统启动时创建,用来保存类的实例。 d. Copy是浅拷贝,
? 深复制
?从文件读取:通过NSKeyedUnarchiver的unArchiverObjectWithFile:方法将创建的归档文件读入执行程序中 // Program 19.4
#import
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; NSDictionary *glossary;
glossary = [NSKeyedUnarchiver unarchiveObjectWithFile: @\for ( NSString *key in glossary )
NSLog (@\[pool drain]; return 0; }
Program 19.4 Output:
abstract class: A class defined so other classes can inherit from it. adopt: To implement all the methods defined in a protocol archiving: Storing an object for later use.
编码方法和解码方法
?可以使用以上的方法归档和恢复NSStrng、NSArray、NSDictionary、NSSet等基本的Objective-C类对象
?通常自定义的类不能直接归档,比如归档AddressBook,若对其归档则会出现如下的错误提示
?若要归档必须使该类遵守
?编码方法一般应指定如何归档想要保存的对象中的每个实例变量。 ?下面列出带键的归档中编码和解码的方法
Encoding and Decoding Basic Data Types in Keyed Archives Encoder Decoder
encodeBool:forKey decodeBoolforKey: encodeInt:forKey decodeIntforKey: encodeInt32:forKey decodeInt32forKey: encodeInt64:forKey decodeInt64forKey: encodeFloat:forKey decodeFloatforKey:
encodeDouble:forKey decodeDoubleforKey: ?对于基本的Objective-C类,可以使用
encodeObject:forKey:和decodeObjectforKey:编码和解码
q.使用NSData创建自定义档案
?有时可能不希望使用archiveRootObject:ToFile:方法将对象直接写入文件,而是临时放到有NSData对象创建的临时存储空间中保存
?NSData对象用来保存一块内存空间作为临时存储数据的空间 dataArea1 =[NSMutableData data]; dataArea2 =[NSData data];
Xcode会打开objc.h文件: typedef signed char BOOL; #define OBJC_BOOL_DEFINED #define YES (BOOL)1 #define NO (BOOL)0
我们看到这段代码,我们可以这样理解,在Objective-C里面,BOOL其实是signed char,YES是1,NO是0。我们可以这样给BOOL赋值: BOOL x = YES; BOOL y = NO;
关于BOOL,实际上就是一个开关的变量,但是我们需要注意下面2点: 第一点,从本质上来说BOOL是一个8bit的一个char,所以我们在把其他比如说short或者int转换成为BOOL的时候一定要注意。如果short
或者int的最低的8位bit都是0的话,尽管除了最低的8位以外都不是0,那么经过转换之后,就变成了0也就是NO。比如说我们有一个int的值是0X1000,经过BOOL转换之后就变成了NO。
第二点,Objective-C里面的所有的逻辑判断例如if语句等等和C语言保持兼容,如果数值不是0判断为真,如果数值是0那么就判断为假,并不是说定义了BOOL值之后就变成了只有1或者YES为真。(非零即真)所以下面的代码的判断都为真: if(0X1000) if(2) if(-1)