一、C结构体与Objective-C类之间:
共同点:C结构体是一块内存,对象也是一块内存。C结构体有数据成员,每个数据成员有名称和类型。与之类似,对象有实例变量,每个实例变量也有名称和类型。
不同点:类有方法。方法和函数类似,也有名称,返回类型和一组期望传入的参数。此外,方法还可以访问对象的实例变量。要调用某个对象的方法,可以向该对象发送相应的消息。而C结构体则是通过函数指针的方式 “return_type (*method_name)(param_type param_name)”,为其添加方法;
二、Objective-C允许向某个值为nil的变量发送消息,且不会发生任何事情。在其他语言中,向空指针(值为0的指针)发送消息是非法的,因此需要先检查指针是否为空。
三、快速枚举:
Objective-C快速枚举比传统的for循环简洁很多,出错率更低,而且经过编译器的优化,通常比for循环更快。~_~...
for ( id obj in array ) {
//处理逻辑....
}
*_* 快速枚举有个限制:如果需要在循环体中添加或删除对象,就不能使用快速枚举,否则程序会抛出异常。这是只能使用计数器并使用普通的for循环。
四、格式字符串:
Objective-C的格式字符串基本和C语言相同。但Objective-C支持一种额外的转换说明:%@,对应的实参类型是指向任何一种对象的指针。程序在处理格式字符串时,如果遇到%@,则不会将其直接替换为相应位置的实参。程序会先向相应位置的实参发送description消息,得到description方法所返回的NSString对象,然后使用得到的NSString 对象替换%@。因为程序会向%@所对应的实参发送消息,所以这些实参必须是对象。
五、实例变量:
声明类的实例变量时,需要将相应的声明写在花括号里,并紧跟在类声明的后面。同时在Objective-C语言中,实例变量的变量名之前通常会加上一个下划线(语言规范)。为了访问该变量,则需要创建存取方法。然而在使用点语法进行存取时,其下划线将不再显示。不加下划线,也并不会有影响(语言规范)。~_~...
#import <Foundation/Foundation.h>
@interface BNRItem : NSObject
{
NSString *_itemName;
int _valueInDollars;
}
- (void) setItemName:(NSString *)item_name;
- (NSString *)itemName;
- (void) setValueInDollars:(int)v;
- (int) valueInDollars;
@end
六、指定初始化方法:
任何一个类,无论有多少个初始化方法,都必须选定其中一个做为指定初始化方法(designated initializer)。指定初始化方法要确保对象的每个实例都处在一个有效的状态。有效(valid)一词有很多不同的意思,这里是指向初始化后的对象发送消息时,输出结果是可预期的,并且不会有‘坏事’发生。😏
"instancetype" 该关键字表示方法的返回类型和调用方法的对象类型相同。在OC(Objective-C)中,一个对象不能同时拥有两个选择器相同、但返回类型(或者参数类型)不同的方法。为了避免这个问题,可以声明init方法的返回类型和调用方法的对象类型相同,这样就保证了对象初始化后任然是正确的类型。初始化方法推荐使用该类型。
"id"在OC 引入instancetype关键字之前,初始化方法的返回类型都是id(读音“eye-dee”)。id的定义是“指向任意对象的指针”(id和C语言的void* 类似)。
instancetype & id :
instancetype只能用来表示方法返回类型,id 可以用来表示变量和方法参数的类型。如果程序运行时无法确定一个对象的类型,就可以将该对象声明为id.同时instancetype能够确定对象的类型,能够帮助编译器更好的为我们定位代码书写的问题。
注意初始化方法的核心代码:
初始化实例变量,不要直接访问实例变量,而要使用存取方法。但是初始化方法中相反,应该直接访问实例变量。理由:“初始化方法在执行时,无法确定新创建对象的实例变量是否已经处于正确设置。实例变量可能具有不确定的值,也可能没有被正确分配,如果这时调用存取方法访问实例变量,则很可能会引起错误❌”。
初始化方法规则:
.类会继承父类所有的初始化方法,也可以为类加入任意数量的初始化方法
.每个类都要选定一个指定初始化方法
.在执行其他初始化工作之前,必须先用指定初始化方法调用父类的指定初始化方法(直接或间接)
.其他初始化方法要调用指定初始化方法(直接或间接)
.如果某个类所声明的指定初始化方法与其父类不同,就必须覆盖父类的指定初始化方法并调用新的指定初始化方法(直接或间接)
七、头文件中的声明顺序:
实例变量声明应该写在最前面,然后是类方法,接下来是初始化方法,最后是其他方法。这种排列顺序是一种约定,可以使头文件更容易阅读。
八、NSArray
OC中的数组可以存储不同类型的对象,对于很多强类型的语言则是不被允许的。但该数组只能保存执行Objective-C对象的指针,所以对于基本类型(primitive)的变量或C结构,需要先将它们“包装”成OC对象即可。
注意,不能将nil加入数组对象。如果要将“空洞”加入数组对象,就必须使用NSNull对象。NSNull对象的作用就是代表nil,起到占位的作用。
数组数据存取时,推荐使用下标语法。坚持使用点语法和下标语法可以清晰的突出消息发送代码,也可以避免代码过于冗长。因为方括号的作用可能不同,容易产生混淆:有的是发送消息,有的是存取方法,有的是访问数组中的对象。
*_* 随机整数&随机字符:
[NSString stringWithFormat:@“%c%c”,‘0’ + arc4random( ) % 10,‘A’ + arc4random ( ) % 26];
九、#import 和 @import
#import ~~编译器会使用C语言的预处理器将所有需要的头文件拷贝到文件中,同时也可确保引用的文件只会被引用一次,这样就不会陷入递归包含的问题中。但随着项目中需要使用的框架越来越多,编译器也会花费越来越长的时间处理大量重复的头文件。为了解决这个问题,Xcode为所有项目添加了一个预编译头文件(precompiled header file)XX-Prefix.pch,第一次编译项目时,预编译头文件中列出的文件被编译并缓存,编译器会重复使用缓存结果快速编译项目中的其他文件。~~这种方式在一定时期内很好的满足了Objective-C程序员对编译速度的要求,但是Apple发现在项目中维护.pch文件低效耗时,因此继续优化编译器并引入了@import指令,该指令会优化预编译头文件和缓存编译结果的过程。同时,文件中不用再明确引用框架---编译器会根据@import自动导入相应的框架。