2Objective-C
使用实例
Objective-c,方法的唯一性取决于方法名,因此,即使参数类型或返回类型不同,一个类也不能有两个名称相同的方法。
消息和方法:方法是指一块可以执行的代码,消息是指要求类或对象执行某个方法的动作。消息的名称和将要执行的方法的名称一定是相同的。
nil是值为0的指针,对应C语言中的NULL和Java中的null
创建NSString对象
@为前缀的NSString是hard-coded的字符串。
格式字符串:
NSLog的实参个数并不确定,其中第一个实参是必须的,且必须是NSString对象。这个实参称为格式化字符串(format string),可以包含文字和多个转换说明(token)。格式字符串中的转换说明(格式规格)必须以%为前缀。
和printf相比,NSLog支持一种额外的转换说明:%@,对应的实参类型是任何一种对象。程序在处理格式字符串时,如果遇到%@,则不会将其直接替换成相应位置的实参,程序会先向相应位置的实参发送description消息,得到description方法所返回的NSString对象,然后得到的NSString对象替换%@。因为程序会向%@所对应的实参发送消息,所以这些实参必须是对象。又因为每个对象都实现了description方法,所以任何对象都可以对应%@
NSArray和NSMutableArray
数组对象包含一组按序排列的对象,可以通过索引存取。
在Objective-c中,数组对象所包含的“对象”并不是对象本身,而只是指向对象的指针(该对象在内存中的地址),所以不能将基本类型primitive的变量或者C结构加入数组对象。
如果想要将nil加入数组中,则必须使用NSNull对象,NSNull对象的作用就代表nil[NSNull null]
创建 Objective-C类的子类
NSObject作为位于层次结构顶部的父类,其职责是实现Cocoa Touch中的每个对象的基本行为。NSObject实现了很多方法,其中包括alloc、init、description方法。
description:向某个NSString发送description消息时,可以得到一个NSString对象,这个NSString对象会包含当前对象的类名和其在内存中的地址信息<QuizViewControllrt:0x4b222a0>。
实例变量:
声明类的实例变量时,需要将相应的声明写在花括号里面,并紧跟在类的声明后面。
存方法:将传入的对象指针赋给了相应的实例变量
取方法:返回指针,指向相应的实例变量所指向的对象。
对于实例变量(例如int型):存方法将传入值直接赋给实例变量,取取方法则是直接返回相应的实例变量的值。
实例方法:
初始化方法initializer,无论有多少个初始化方法,都必须选定其中一个做为指定初始化方法(designated initializer),指定初始化方法要确保对象的每一个实例变量都处在一个有效的状态。
-(id) initWithItemName:(NSString *)name valueInDollars:(int)value serialNumber:(NSString *)sNumber;
id相当于C语言中的void*,指向任意对象。
使用id的原因:子类会继承父类的全部方法。在OC中一个对象不能同时拥有两个选择器相同,但返回值类型(参数类型)不相同的方法。
isa
任何一个对象都可以通过自己的isa指针,知道自身的类型。
任何一个对象都有一个名为isa的实例变量(is a 是一个)。
在程序向某个类发送alloc消息并创建对象后,相应的类会为新创建的对象的isa实例变量赋值,将其指回自己,即创建该对象的类。
在运行时,当某个对象收到消息后,会根据isa指针所指向的类,执行和相应的消息相匹配的方法。
self:
self存在于方法中,是一个隐式implicit 局部变量(相当于this),通常情况下,self会用来向对象自己发送消息。
super:
在覆盖某个类的某个方法时,往往需要保留该方法在父类中的实现,然后在其基础上扩充子类的实现。OC提供了一个名为super的编译器指令(compiler directive)。
其他初始化方法与初始化方法链
- (id)initWithItemName:(NSString *)name{
return [self initWithItemName:name valueInDollars:0 serialNumber:@""];}
这种串联chain使用初始化方法的机制可以降低出错的概率,也容易维护代码。
总结:
每个类都要选定一个初始化方法
其他方法要调用指定初始化方法
如果某个类所声明的指定初始化方法与其父类的不同,就必须覆盖父类的指定初始化方法并调用新的指定初始化方法。
类会继承父类所有的初始化方法,也可以为类加入任意数量的初始化方法。
类方法:
OC方法分类类方法class method和实例方法instance method。
通常情况下,类方法的作用是创建类实例,或者获取类的某些全局属性,类方法不会作用在实例上,也不能存取实例变量。
在Objective-C中,如果某个类方法的返回类型是类的实例(例如stringWithFormat:),就可以将这种类方法称为便捷方法(convenience method)
在便捷方法中应该使用self,而不应该使用类的类名,这样子类也能够使用父类的便捷方法,不至于发生错误。
Item *newItem = [[self alloc] initWithName:randomName valueInDollars:randomValue];
return newItem;
规则:
声明方法时的代码位置:类声明应该写在最前面,然后是初始化方法,最后是其他方法。
异常与未知选择器
OC是动态类型语言(dynamically typed language),无法在编译时(即构建应用程序时)判断某个对象是否 响应相应的消息。如果Xcode判断应用会向某个对象发送其无法响应的消息,就会显示相应的警告信息,但是代码仍然能够编译通过。
由于某些原因,如果应用最后还是向某个对象发送了其无法响应的响应的消息,那么程序就会抛出异常(exception)。异常也称为运行时错误(run- time error),这是因为异常只会在应用运行时才会出现。和运行错误相对应的是编译时错误,编译时错误只会在构建应用或编译代码时出现。
异常的描述信息中,其实部分会列出日期,时间和应用名称,***之后显示异常原因,例如:未知选择器(unrecognized selector)
行首的-代表接受方是实例。+代表接受方是类
类命名:
名字空间冲突(namespace collision)其他编程语言会引入名字空间(namespace)机制来解决这类问题的。
OC没有提供名字空间机制,所以最好 增加前缀 2-3个字符
使用__weak关键字,可以将某个变量声明为具有弱引用特性,弱引用特性一个很功能:当程序释放了某个对象后,会自动将指向该对象的具有弱引用特性的指针全部设置为nil
属性:通过属性可以为类声明实例变量并实现相应的存取方法。
声明属性
@property (nonatomic, readwrite, strong) NSString *str;
默认readwrite atomic assign
合成属性@synthesize
在 64-bit时,运行时系统会自动给类添加 ivar,添加的 ivar 以一个下划线”_”做前缀。上面声明部分的 @synthesize window=_window; 意思是说,window 属性为 _window 实例变量合成访问器方法。也就是说,window属性生成存取方法是setWindow,这个setWindow方法就是_window变量的存取方法,它操作的就是_window这个变量。通过这个看似是赋值的这样一个操作,我们可以在@synthesize 中定义与变量名不相同的getter和setter的命名,籍此来保护变量不会被不恰当的访问
实例变量与属性
属性可以自动生成存取方法和实例变量。
默认情况下,合成属性后得到的存取方法,针对的是和该属性有相同名称的实例变量。合并属性后,如果没有与之匹配的实例变量,那么编译器会自动创建一个。因此,如果为某个类声明了属性,并且合成了属性,就可以不用声明相应的实例变量。
copy特性
通常情况下,当某个属性是指向其他对象的指针,而且该对象的类有可修改的子类(例如NSString或NSArray)时,最好先复制该对象,然后再将指针指向复制后的对象,这种模式更安全。(编写具有防御性的代码)
itemName = [str copy];
先向str所指向的对象发送了copy消息,该对象的copy方法会返回一个新的NSString实例(不是NSMutableString实例),并且其拥有的数据会和收到copy消息的那个对象相同。接着方法会为实例变量itemName赋值,指向新的NSString实例。至于所有权,copy方法返回的是拥有强引用特性的指针,而收到copy消息的对象不会发生任何变化:该对象不会获得也不会失去拥有方,其数据也不会发生任何变化。
用点号调用存取方法Dot Syntax
使用方括号调用存取方法会使(程序是在向对象发送消息)的事实。
Autorelease池与ARC历史
当对象收到autorelease消息时,某个autorelease池会成为该对象的拥有方。这样可以解决这类问题:某个方法创建了一个新的对象,但是创建方又不需要成为该对象的拥有方。为了能返回新创建的对象,同时避免提前释放问题,就可以向新创建的对象发送autorelease消息。便捷方法依赖autorelease池,因为只有借助autorelease池,便捷方法才能将新创建的实例返回给调用方,又不产生内存管理问题。
便捷方法的代码示例如下:
- (Item *)someItem {Item *item = [[[Item alloc] init] autorelease]; return item;}

浙公网安备 33010602011771号