《Write Objective-C Code》学习笔记

时间:2022-08-01 22:27:21

原文 http://blog.cocoaxcode.com/2012/07/%E3%80%8Awrite-objective-c-code%E3%80%8B%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/

1、对象是类的一个实例。不同对象的实例变量都有独立的内存空间,但这些对象的方法都是类共有的。这与C++完全一致。

2、.h头文件,包含类、类型、函数、常量的声明。.m源码文件,包含Objective-C与C代码。.mm源码文件,如果用到了C++的用法,放在这里。

3、使用#import方法,而不是#include方法引用头文件,这样可以避免头文件重复包含的问题。

4、NSObject是所有类的根类。

5、类声明(class declaration)
@interface 类名 : 超类
{
实例变量声明(可选)
}

方法声明

@end

6、类实现(class implementation)
#import “类.h”

@implementation 类名

方法实现

@end

7、Objective-C中,对于对象的引用总是使用指针。这与C++不同!

8、可以使用id类型引用任意类的对象。id类型是一种暗含的对象指针类型,声明时不需要加*。正确的用法是:id  anyObject;。其他情况则需要加*来显式的指出声明的是一个对象指针类型,例如:NSString  *aString;。

9、Objective-C中,方法分为两种:实例方法(-)与类方法(+)。

10、方法声明(method declaration)
大于一个参数:
+/- (返回类型)方法名:(参数类型)参数名 参数标识:(参数类型)参数名;
此方法被称作“方法名:参数标识:”——冒号不能丢,调用时冒号后面是相应的输入参数

只有一个参数:
+/- (返回类型)方法名:(参数类型)参数名;
此方法被称作“方法名:”——冒号不能丢,调用时冒号后面是相应的输入参数

没有参数:
+/- (返回类型)方法名;
此方法被称作“方法名”——没有任何参数,因此没有冒号

11、实例方法调用(invoking an instance method,messaging an instance method)
[接收消息的对象 方法名:参数 参数标识:参数];
[]表达式支持嵌套使用。嵌套使用时,[]可以替换接收消息的对象或方法中的参数。

12、点语法(dot syntax)
对象.实例变量名;
使用点语法可以简便的调用存取方法。

13、类方法调用(invoking a class method,messaging a class method)
[接收消息的类 方法名:参数 参数标识:参数];
直接向类发送消息进行调用,使用这种调用的方法必须是类方法。一个类实际上就是类型Class在运行时创建的一个对象。类方法与C++中的类静态方法类似。类方法常用来作为工厂方法来创建新的实例对象或访问所有与此类相关的共享信息。

14、访问方法(accessor methods)
get方法:
要求与属性名完全相同。调用后返回此属性。

set方法:
使用“set属性名:”的形式,要求属性名首字母大写。调用后设置新的属性。

注:属性即实例变量。命名时要求首字母小写后续每个单词首字母大写。

14、属性声明(property declaration)
@property (选项1, 选项2) 数据类型 属性名;
属性声明需要放在类声明中(@interface … @end之间)。
编译器会根据属性声明来合成相应的get、set方法。

15、合成访问方法(synthesize accessor methods)
@synthesize 属性名;
合成访问方法需要放在类实现中(@implementation … @end之间)。

可以使用合成访问方法自动添加实例变量,方法是:
@synthesize 属性名 = _实例变量名;

注:属性名与实例变量名一般来说应该完全相同的。

16、块(blocks)
块定义:
返回类型 (^保存块的变量名)(参数类型) = ^(参数类型 参数名) { 块实现 };

块类型:
返回类型 (^)(参数类型)

块调用:
返回值 = 保存块的变量名(参数);

块定义、块类型、块调用都与函数指针几乎完全相同。

块可以访问其定义所在方法的(即块外部的):局部变量、参数,及此方法所能访问的函数、全局变量、实例变量。这种访问是只读的。

如果块外部的变量声明中含有__block标识,则其可以在块内部被修改。

即使块定义所在的方法或函数返回了,只要块还有效(即至少有一个引用指向它),那么块所引用的局部变量会被作为块对象的一部分保留。

使用块可以简单便捷的实现函数回调。

17、协议(protocols)
用协议声明的方法可以被任何类实现,即使这些类没有公共的超类。这比C++的虚方法更灵活。使用协议可以声明那些需要被其他类实现的接口。实现了协议声明的方法的类被称作符合这个协议。需要在类的声明中指定类所符合的协议,形式如下:
@interface 类名 : 超类 <所符合的协议>
注:
超类与所符合的协议没有必然联系,只是写得比较近而已。

协议声明:
@protocol 协议
方法声明(默认是必选)

@required
必选方法声明

@optional
可选方法声明

@end
注:
协议声明与类声明很类似,不过协议没有超类,还有它也不能定义实例变量(但可以声明属性)。

18、类别(categories):
类别是Objective-C另一个很有个性的特性。使用它可以很便捷的向已有类直接注入新的方法,而不是C++那样先继承已有类,然后在子类中新增方 法。通过类别新增的方法成为了类(包括其子类)的一部分。可以向类(包括其子类)的任何一个实例发消息以调用在类别中定义的方法。

类别的另一个主要用途是归类放置一个类的不同方法。可以把一个类的相关方法放在一块,甚至把这些方法分别放在不同的文件里,以便协同开发与维护。

其实之所以叫类别,我猜当初设计这个特性的本意应该是给类的方法归类,而不是为了给类新增方法。因为这种新增方法的实现方式可以破坏类的封装。

关于类别这个特性,后续再展开详细学习。这里先给出声明与实现类别的形式。
类别声明:@interface 类名 (类别名)
类别实现:@implementation 类名 (类别名)

19、部分常见的已定义类型(defined types)
id类型:任意的对象类型。无效值是nil。
Class类型:任意的类类型。无效值是Nil。
SEL类型:selector类型,所对应的数据是一个方法签名(可用其直接调用相应的方法)。无效值是NULL。
BOOL类型:布尔类型。使用YES表示真、NO表示假。

注:
向值为nil的对象发消息,不会crash,代码会继续执行。
如果所调用的方法的返回类型是一个对象,那么所得到的返回值也是nil。
返回类型是数值类型或指针类型,返回值会是0。其他复杂类型的返回值不确定。
依据以上特性来编写代码,可以减少对象是否为nil的判断,使代码更简洁。

20、self与super
self:是一个本地变量,指向所在对象本身。相当于C++中的this。向self发送消息时,会首先在对象本身寻找所调用的方法,如果没有找到,则会向超类一直找下去。
也可以将其用在点语法中,来获取或设置实例变量。

super:向super发送消息时,会首先在超类寻找所调用的方法。

注:
当通过super调用超类实现的方法时,在超类的实现中任何引用的self仍然指向原始的对象,即子类的实例。如果超类的实现去调用另一个类的方法,且此方法被子类覆盖,那么所调用的是子类的实现。

最后提一点,Objective-C与C++相比,支持子类覆盖超类的方法,而不支持同一个类中重载方法。

 

参考资料:
1. Write Objective-C Code
2. Learning Objective-C 2.0