消息表达式
消息表达式使用方括号([ 和 ])将消息本身(以及任何所需参数)括起来,同时将接收消息的对象放在最左边方括号右侧。例如,要将 insertObject:atIndex: 消息发送给 myArray 变量保存的对象,您会使用以下语法:
[myArray insertObject:anObject atIndex:0];
[[myAppObject theArray] insertObject:[myAppObject objectToInsert] atIndex:0];
[myAppObject.theArray insertObject:myAppObject.objectToInsert atIndex:0];
类方法
要么将类方法用作工厂方法创建类的新实例,要么访问与该类关联的一些共享信息。类方法声明的语法,与实例方法声明的语法相同,只是方法类型标识符使用加号 (+),而非减号。
NSMutableArray *myArray = nil; // nil is essentially the same as NULL
// Create a new array and assign it to the myArray variable.
myArray = [NSMutableArray array];
属性方法
属性的基本声明使用 @property 编译器指令,后面紧跟属性的类型信息和名称。
编译器自动合成所声明的属性。在合成属性时,它创建自己的存取方法,以及“支持”该属性的专有实例变量。实例变量的名称与属性的名称相同,但具有下划线前缀 (_)。只有在对象初始化和取消分配的方法中,您的应用程序应该直接访问实例变量(而不是其属性)。
如果您想要让实例变量采用不同名称,可以绕过自动合成,并明确地合成属性。在类实现中使用 @synthesize 编译器指令,让编译器产生存取方法,以及进行特殊命名的实例变量。例如:
@synthesize enabled = _isEnabled;
同时,在声明属性时,您可以指定存取方法的自定名称,通常是使 Boolean 属性的 getter 方法遵循约定形式,如下所示:
@property (assign, getter=isEnabled) BOOL enabled; // Assign new value, change name of gette
块 block
您接着可以调用块变量,就像它是一个函数一样:
int result = myBlock(4); // result is 28
块共享局部词法作用范围内的数据。块的这项特征非常有用,因为如果您实现一个方法,并且该方法定义一个块,则该块可以访问该方法的局部变量和参数(包括堆栈变量),以及函数和全局变量(包括实例变量)。这种访问是只读的,但如果使用 __block 修饰符声明变量,则可在块内更改其值。即使包含有块的方法或函数已返回,并且其局部作用范围已销毁,但是只要存在对该块的引用,局部变量仍作为块对象的一部分继续存在。作为方法或函数参数时,块可用作回调。被调用时,方法或函数执行部分工作,并在适当时刻,通过块回调正在调用的代码,以从中请求附加信息,或获取程序特定行为。块使调用方在调用时能够提供回调代码。块从相同的词法作用范围内采集数据(就像宿主方法或函数所做的那样),而非将所需数据打包在―关联‖结构中。由于块代码无需在单独的方法或函数中实现,您的实施代码会更简单且更容易理解。
协议和类别
在接口块中,您指定您的类符合或采用一个协议,方法是将该协议的名称,放在尖括号 (<...>) 中,并且放在它继承的类的名称后面。在您的首个 iOS 应用程序中,您指明了采用 UITextFieldDelegate 协议,代码行如下:
@interface HelloWorldViewController :UIViewController <UITextFieldDelegate> {
您无需声明所实现的协议方法。协议的声明,看起来类似于类接口的声明,只是协议没有父类,并且不定义实例变量(尽管它们可以声明属性)。以下示例展示使用一个方法进行一个简单的协议声明:
@protocol MyProtocol
- (void)myProtocolMethod;
@end
class extension
当您开始探索 Objective-C 框架的头文件时,将很快遇到如下的代码行:
@interface NSDate (NSDateCreation)
这行代码通过使用圆括号将类别名称括起来的语法约定,声明了该类别。 类别是 Objective-C 语言的一项功能,可让您扩展类的接口,而无需对类进行子类化。类别中的方法成为类类型的一部分(在程序的作用范围内),而这些方法由类的所有子类继承。您可以将消息发送给类(或其子类)的任何实例,以调用在类别中定义的方法。您可以将类别用作一种手段,来对头文件内的相关方法声明进行分组。您甚至还可以将不同的类别声明放在不同的头文件中。框架在其所有头文件中使用这些技巧,来达到清晰明确。您还可以使用称为类扩展的匿名类别,在实现 (.m) 文件中声明专有属性和专有方法。类扩展看起来类似于类别,只是圆括号之间没有文本。例如,以下是一个典型的类扩展:
@interface MyAppDelegate ()
@property (strong) MyDataObject *data;
@end
类型 描述和字面常量
id 动态对象类型。动态类型化的对象和静态类型化的对象的否定字面常量,都是 nil。
Class 动态类类型。其否定字面常量是 Nil。
SEL 选择器的数据类型 (typedef);此数据类型表示运行时的方法签名。其否定字面常量是 NULL。
BOOL Boolean 类型。字面常量值是 YES 和 NO。
Objective-C 中其他两个重要的保留术语,是 self 和 super。self 和 super 的主要用途,都是发送消息。self 还用于点记法,用于调用由已声明属性合成的存取方法。
__weak 将引用标记为弱。应该将弱引用用于以下种类的引用:
委托
@property(weak) id delegate;
未引用顶级对象的 Outlet
@property(weak) IBOutlet NSString *theName;
目标
(void)setTarget:(id __weak)target;
在块内对 self 的引用
__block typeof(self) tmpSelf = self;
[self methodThatTakesABlock:^ {
[tmpSelf doSomething];
}];
一个块对它所捕捉的变量构成强引用。如果在块内使用 self,该块对 self 构成强引用。因此,如
果 self 也具有对该块的强引用(通常都有),将产生强引用循环。要避免循环,您需要在块外创建
对 self 的 weak(或 __block)引用,如以上例子所示。
速写记法来创建 NSNumber 对象
NSNumber *myIntValue = @32;
NSNumber *myBoolValue = @YES;
NSNumber *myCharValue = @'V';
表示无符号整型 (unsigned integers)、长整型 (long integers)、长长整型 (long long integers) 和浮点值 (float values),方法是将字符―U、―L、―LL和―F分别追加到记号值末尾
arrayWithObjects:count: 和 arrayWithObjects: 方法(及其对应的初始化程序),从一系列对象创建数组。使用前一种方法时,第二个参数指定第一个参数中的对象数;使用后一种方法时,使用 nil 终止以逗号分隔的对象序列。
<span style="font-size:14px;">// Compose a static array of string objects
NSString *objs[3] = {@"One", @"Two", @"Three"};
// Create an array object with the static array
NSArray *arrayOne = [NSArray arrayWithObjects:&(*objs) count:3];
// Create an array with a nil-terminated list of objects
NSArray *arrayTwo = [[NSArray alloc] initWithObjects:@"One", @"Two", @"Three", nil];</span>