重读obj基础教程笔记
p38
@interface 定义类的公共接口,用来提供类的公共描述
通常被成为API application programming interface
@implementation 中可以定义那些在@interface中无相应声明的方法,可以把它们当做是私有方法,仅在类的实现中使用。
事实上,obj中不存在真正的私有方法,也无法把某个方法标识成私有方法,从而禁止其他代码调用它。这是obj动态本质的副作用。
p39
@interface和@implementation间的参数名不同是正确的。如果使用相同的变量名会隐藏初始变量,可以为参数使用新的名称来避免问题。
p64
getter方法engine返回实例变量engine的当前值。记住在obj中所有对象间的交互都是通过指针实现的,所以方法engine返回的是一个指针,指向car中发动机对象
同样,setter方法setEngine:将实例变量engine的值设为方法参数所指向的值。实际上被赋值的并不是engine本身,而是指向engine的指针值。换一种方式说,就是在调用了对象Car中的setEngine:方法后,依然只存在一个发动机,而不是两个
-(Engine *)engine { return (engine); } -(void)setEngine(Engine *)newEngine { engine=newEngine; }
p71
如果用.mm做文件扩展名,编译器就会认为你是用objective-c++编写代码,这样你就可以同事使用C++语言和objective-c来变成了
p74
导入头文件有两种不同的方法:使用引号或者使用尖括号。带尖括号的语句是用来导入系统头文件的,而带引号的语句则说明导入的是项目本地的头文件,尖括号那么这个头文件对你的项目来说是只读的。
p76
如果仔细观察Car类的接口,你会发现它只是通过指针引用了Tire和Engine。这是@class可以完成的工作。
P79
由于AllWeatrherRadial和Slant6是继承其他类而不是通过指针指向其他类,所以不能在头文件中使用@class语句
因为编译器需要先知道所有关于超类的信息才能成功的为其子类编译@interface,它需要了解超类实例变量的配置
p108
一些有用的数据类型
NSMakePoint() NSMakeSize() NSMakeRect()
p109
创建字符串 NSString的stringWithFormat:就是这样通过格式字符串和参数来创建NSString的
+(id)stringWithFormat:(NSString *)format,...;
类方法
加号 OBJ运行时生成一个类的时候,它会创建一个代表该类的类对象。类对象包含了指向超类的指针、类名、和指向类方法列表的指针。类对象还包含一个long型数据,为新创建的类实例对象指定大小。
如果你在申明方法时添加了加号,那么就是把这个方法定义为类方法。这个方法属于对象(而不是类的实例对象)并且通常用于创建新的实例。我们称这种用来创建新对象的类方法为工厂方法。或者访问全局类数据。
p111
== isEqualToString
==:判断指针数值 (判断是否是同一个对象)
isEqualToString:所指的对象 (判断对象的的值是否等价;)
P115
NSArray有两个限制,首先,它只能储存obj的对象,而不能存C语言中的基本数据类型。如int、float、enum、struct或者NSArray中的随机指针。同时,你也不能在NSArray中储存nil(对象的零值或NULL值)
p120
快速枚举
for (NSString *string in array){ NSLog(@"i found %@",string) }
p122
不要试图去创建NSString、NSArray或NSDictionary的子类。通常你可以通过将NSString或NSArray符合到你的某个类或者使用类别,而不是创建子类。因为那是件非常痛苦的事情。
NSArray和NSDictionary 只能存储对象,而不能直接存储任何基本类型的数据,如int、float、或struct。但是你可以用对象来封装基本数值。
用NSNumber
通常将一个基本数据类型的数据包装成对象叫做装箱
NSNumber *number; number = [NSNumber numberWithInt:42]; [array addObject:number]; [dictionary setObject:number forKey:@"Bork"];
从对象中提取基本类型的数据叫做取消装箱
-(char)charValue;
-(char)intValue;
p126
NSFileManager *manager;
manager = [NSFileManager defaultManager];
这在Cocoa中是很常见的,很多类都是单实例构架。
即只需要一个实例,你真的只需要一个文件管理器,或一个字体管理器,或一个图形内容。这些类提供了一个类方法用来访问唯一共享对象,你可以用它来完成你的工作。
p130
当一个对象因其保留计数器归0而即将被销毁时,obj自动向对象发送一条dealloc消息。你可以自爱自己的对象中重写dealloc方法
当对象计数器为0是,自动调用dealloc方法
-(void)dealloc { ... }
P132
如果使用alloc、new、copy来操作一个对象,你只需要释放改对象以销毁它并收回它占用的内存。
如果一个对象具有指向其他对象的实例变量,则称该对象拥有这些对象。
当多个实体拥有某个特定对象时,对象的所有权关系就更复杂了,这也是保留计数器值可能大于1的原因。
如
//Car类的engine setter 方法 -(void)setEngine:(Engine *)engine; //main()函数中调用 Engiine *engine = [Engine new]; [engine setEngine:engine];
问:现在哪个实体拥有engine对象?是main()函数还是Car类
哪个实体负责确保当engine对象不再被使用时能够收到release消息?因为Car类正在使用engine对象,所以不可能是main()函数。因为main()函数随后可能还会使用engine对象,所以也不可能是Car类。
解决办法是让Car类保留engine对象,将engine对象的保留计数增加到2。这是因为Carl类和main()函数这两个实体都正字啊使用engine对象。Car类应该在setEngine:方法中保留engine对象,而main()函数应该释放engine对象。然后Car类完成其任务时再释放engine对象(在dealloc方法中),最后engine对象占用的资源被回收。
p135
NSObject类提供了一个autorelease方法
该方法预先设定了一条在将来某一时刻发送relese消息
当给一个对象发送autorelease消息时,实际上是讲该对象添加到NSAutorelseasePool中,当自动释放池被销毁时,会向该池中的所有对象发送release消息。
p138
内存管理准则
------------------------------------------------------------------------------------------------
获得途径 临时对象 拥有对象
-------------------------------------------------------------------------------------------------
alloc/new/copy 不再使用时释放对象 在dealloc方法中释放对象
在任何其他方法 不需要执行任何操作 活的对象时保留,在dealloc方法中释放对象
p141
垃圾回收
Build --> objective-c carbage collection required[-fobjc-gc-only],这个选项是为了使代码既支持垃圾回收又支持对象的保留和释放,例如两种环境都使用的代码库。
注意:在iphone开发时不能使用垃圾回收,苹果公司建议你不要在自己的代码中写autorelease。同时还要避免使用创建自动释放对象的便利函数。
Cocoa 中关于对象及其保留计数器的3条规则
1.如果使用new、alloc、copy操作获得一个对象,则该对象的保留计数器值为1
2.如果通过任何其他方法获得一个对象,则假设该对象的保留计数器值为1,而且已经被设为自动释放。
3.如果保留了某个对象,则必须保持retain方法和release方法的使用次数相等。
p146
初始化时做什么
可以等到调用者需要时再创建对象,这种技术被称为惰性求值。如果要再自己的init方法种创建复杂但实际课能用不上的对象,则实用这种技术可以提高程序的性能
p159
当父类有多个初始化方法,则需要指定初始化函数,用指定初始化函数执行初始化操作。子类使用其父类的指定初始化函数实现父类的初始化,通常接受参数最多的初始化方法最终称为指定初始化函数。
-(id)init { if(self = [self initWithPressure:34 treadDepth:20]) {} return(self); } -(id)initWithPressure:(float)p { if(self = [self initWithPressure :p treadDepth:20.0]) {} return(self); } .....
p160
初始化函数规则
不需要为你自己的类创建初始化函数方法。如果不需要设置任何状态,或者只需要alloc方法将内存清零的默认行为,则不需要担心init
如果构造了一个初始化函数,则一定要在你自己的指定初始化函数中调用父类的指定初始化函数
如果初始化函数不止一个,则要选择一个作为指定初始化函数。被选定的方法应该调用父类的指定初始化函数
p161
Cocoa 中,分配和初始化是两个分离的操作:来自NSObject 的类方法alloc为对象分配了一块内存区域并将其清零,实例方法init用于获得一个对象并使其运行。
p162
在编写访问器时,如果属性时对象,则需要保留新对象,并释放旧对象。
苹果公司在objective-c 2.0 中引入了新的特性(property)
p172
当实例名称和属性名称不一致时, 只需要@synthesize name(属性) = names(实例)
在后面的调用中 self.name(属性) 该语句的作用时消除歧义,使编译器知道我们期望使用访问器方法访问name,如果直接使用裸名,编译器将假设我们直接修改了实例变量
p173
特性不支持需要接受额外参数的方法。
p174 点表达式
如果表达式出现在等号(=)左边,该属性名称的setter方法将被调用 dealie.blah = gereeble; [dealie setBlah:gereeble];
如果点表示法出现在对象变量右边,则该属性名称的getter方法 shronk = dealie.greenle shronk = [dealie greenle];
p175
为现有的类添加新方法。
p176
声明类别
@interface NSString (NumberConvenience) -(NSNumber *) lengthAsNumber; @end
只要保证类别名称的惟一性,你可以向一个类中添加任意多的类别
p178
1.不能添加新的实例变量
2.名称冲突,一般在自己的类别方法名中增加一个前缀,确保不发生名称冲突。冲突时,类别又更高的优先权。
说明:也又一些技术可以克服类别无法增加新实例变量的局限,例如,可以使用全局字典存储对象与你想要关联的额外变量之间的映射 ( 没理解)
类别的作用
1.将类的实现分散到多个不同文件或多个不同框架中 (例:NSwindows 有数百个方法,如果在一个文件中,太庞大。所以用类别)
2.创建对私有方法的前向应用
如果其他类中的方法未实现,在你访问其他类的私有方法时编译器报错
这时使用类别,在类别中声明这些方法(不必提供方法实现),编译器就不会再产生警告
p185
3.向对象添加非正式协议
要成为一个委托对象,只需要实现已经打算调用的方法。不需要在@interface中声明方法。
balabala一片没有看懂 p187-p188
p190
正式协议
采用协议意味着要实现该协议的所有方法,否则编译器就会生成警告来提醒你。
声明协议
@protocol NSCopying
-(id) copyWithZone:(NSZone *)zone;
@end
协议名称必须惟一,使用协议不引入新的实例变量。
采用协议
@interface Car : NSObject <NSCopying,NSCoding> { ... } @end
p192
浅层复制和深层复制,深层复制是复制了所有的引用对象,例如NSArray 的copy方法,如果array里有5个对象,用浅层复制将只得到5个对象,深层复制得到10个对象,每个对象最终获得一个指向字符串对象的指针对象。
p214
Cocoa提供了两个通用的文件处理类:属性列表和对象编码。属性列表类又NSArray,NSDictionary,NSString,NSDate和NSData.
[NSDate date] 获取当前的日期和时间,它是一个自动释放对象。
未完待续...