Write Objective-C Code
If you haven’t programmed for either OS X or iOS, you need to become acquainted with the primary programming language, Objective-C. Objective-C is a not a difficult language, and once you spend some time with it you’ll find it elegant as well. The Objective-C language enables sophisticated object-oriented programming. It extends the standard ANSI C programming language by providing syntax for defining classes and methods. It also promotes dynamic extension of classes and interfaces that any class can adopt.
如果你既没有过OS X编程,也没有过iOS编程经历,你需要熟悉一下主要编程语言,Objective-C. Objective-C 不是一种难的语言,一旦你使用它一段时间后,你会发现它很优雅。 Objective-C支持面向对象编程。它通过提供语法定义类和方法来扩展标准ANSI C 编程语言。 它也提供(promotes)了任何别的类可以动态扩展的类和接口。
If you are familiar with ANSI C, the following information should help you learn the basic syntax of Objective-C. And if you have programmed with other object-oriented languages, you’ll find that many of the traditional object-oriented concepts, such as encapsulation, inheritance, and polymorphism, are all present in Objective-C. If you are not familiar with ANSI C, it’s a good idea to at least read an overview of the C language before you attempt to read this article.
如果你熟悉ANSI C, 接下来的信息应该能帮助你学习Objective-C 的基本语法。 如果你已经有过别的面向对象语言的编程经验, 你将发现很多传统的面向对象概念,比如封装(encapsulation), 继承(inheritance), 和多态性 (polymorphism) 在Objective-C里也有。如果你不熟悉ANSI C,最好至少学习一个C语言的大概,然后再开始尝试学习本文章。
The Objective-C language is fully explained in The Objective-C Programming Language.
Objective-C语言已在The Objective-C Programming Language 一书里全名阐述。
Objective-C is a Superset of the C Language
Objective-C 是 C 语言的一个超集
The Objective-C language specifies a syntax for defining classes and methods, for calling methods of objects, and for dynamically extending classes and creating programming interfaces adapted to address specific problems. As a superset of the C programming language, Objective-C supports the same basic syntax as C. You get all of the familiar elements, such as primitive types (int
, float
, and so on), structures, functions, pointers, and control-flow constructs such asif...else
and for
statements. You also have access to the standard C library routines, such as those declared instdlib.h
and stdio.h
.
Objective-C 语言指定了定义类和方法的语法,用来调用(calling) 对象的方法, 和 动态扩展(dynamacally extending)类,以及 创建适应于解决(address)具体问题的编程接口。Objective-C 作为C语言的一个超集,它同样支持C的基本语法。 你能获取所有熟悉的元素,比如原始类型(int, float, 等),结构(structures), 函数(functions),指针(pointers) 以及 控制流结构(control-flow constructs) -- 比如 if....else 和 for 语句。 你还可以使用C标准库(standard C library)里的例程(routines), 比如在stdlib.h 和 stdio.h里申明的那些。
Objective-C adds the following syntax and features to ANSI C:
Objective-C 添加了如下语法和功能到 ANSI C:
-
Definition of new classes
新类的定义
-
Class and instance methods
类和实例方法
-
Method invocation (called messaging)
方法调用(称为 消息)
-
Declaration of properties (and automatic synthesizing of accessor methods from them)
特性的声明(和存取方法的自动集成(synthesizing))
-
Static and dynamic typing
静态和动态类型
-
Blocks—encapsulated segments of code that can be executed at any time
块 --任何时候都可以被执行的封装代码段(encapsulated segments)
-
Extensions to the base language such as protocols and categories
对基本语言的扩展,比如协议(protocols)和类别(categories)
Don’t worry if these aspects of Objective-C are unfamiliar to you now. As you progress through the remainder of this article, you will learn about them. If you’re a procedural programmer new to object-oriented concepts, it might help at first to think of an object as essentially a structure with functions associated with it. This notion is not too far off the reality, particularly in terms of runtime implementation.
别担心,如果你现在还不熟悉这些方面。 随着你继续学习本文章,你会了解(learn about)它们。如果你对于面向对象的概念不了解,或许一开始把一个对象想象成一个结构和跟结构相关联的函数的结合对于会有帮助。
In addition to providing most of the abstractions and mechanisms found in other object-oriented languages, Objective-C is a very dynamic language, and that dynamism is its greatest advantage. It is dynamic in that it permits an app’s behavior to be determined when it is running (that is, at runtime) rather than being fixed when the app is built. Thus the dynamism of Objective-C frees a program from constraints imposed when it’s compiled and linked; instead it shifts much of the responsibility for symbol resolution to runtime, when the user is in control.
除了在别的面向对象语言中发现的绝大多数抽象(abstractions)和机制(mechanisms)外,Objective-C 是一个非常动态的语言,而且动态是它最大的优点。它的动态允许一个应用程序的行为(app's behavior)可以在它运行的时候(runtime)决定,而不需要在应用构建时就绑定。 因而Objective-C的动态性让一个程序从它的编译(compiled)和链接(linked)的限制(constrains imposed)中释放出来;而且(instead)当用户在控制时,给运行时(runtime)的符号解析(symbol resolution)转移了很多责任。
Classes and Objects
As in most other object-oriented languages, classes in Objective-C support the encapsulation of data and define the actions that operate on that data. An object is a runtime instance of a class. It contains its own in-memory copy of the instance variables declared by its class and pointers to the methods of the class. You create an object in a two-step procedure called allocation and initialization.
正如大多数别的面向对象语言, Objective-C 里的类支持数据的封装(encapsulation of data), 并且定义能操作这些数据的动作(actions)。 对象是类在运行时(runtime)的实例(instance)。 它包含了它自己由类定义的实例变量(instance variables)在内存中的副本,以及指向类方法的指针。 你可以分2步创建一个对象--- 分配(allocation) 和 初始化(initialization).
The specification of a class in Objective-C requires two distinct pieces: the interface and the implementation. The interface portion contains the class declaration and defines the public interface of the class. As with C code, you define header files and source files to separate public declarations from the implementation details of your code. (You can put other declarations in your implementation file if they are part of the programmatic interfaces but are meant to be private.) These files have the filename extensions listed in the following table.
在Objective-C 中,一个类的规范(specification)需要两个部分:接口(interface) 和 实现(implementation)。接口部分包含 类的声明 和 类公共接口的定义。 正如C代码,你定义头文件(header file) 和 资源文件(source file) 来分离公共声明(public declarations) 和 它的具体实现(implementation details)代码。 (你可以把其他声明放在实现文件,如果它们是编程接口(programmatic interfaces)的一部分, 但是是似有的。) 这些文件的文件扩展名列在下表:
Extension |
Source type |
---|---|
|
Header files. Header files contain class, type, function, and constant declarations. |
|
Implementation files. A source file with this extension can contain both Objective-C and C code. It is sometimes called an source file. |
|
Implementation files. A source file with this extension can contain C++ code in addition to Objective-C and C code. Use this extension only if you actually refer to C++ classes or features from your Objective-C code. |
When you want to include header files in your source code, specify a pound import (#import
) directive as one of the first lines in a header or source file; a #import
directive is like C’s #include
directive, except that it makes sure that the same file is never included more than once. If you want to import some or all of the header files of a framework, import the framework’s umbrella header file, which has the same name as the framework, and not individual header files. The syntax for importing the header files of the (hypothetical) Gizmo framework is:
当你想要在你的源代码文件里包含头文件时,在头文件或资源文件的开始处使用一系列的#import语句;#import 指令 就相当于 C里的#include指令,除了它只载入同一个文件一次。如果你想 导入(import)一个框架全部的头文件或其中一些,导入该框架中跟框架同名的伞头文件(umbrella header file),而不需单独导入其中的单个头文件。 比如,导入 Gizmo 框架的头文件语法如下:
#import <Gizmo/Gizmo.h> |
The diagram below shows the syntax for declaring a class called MyClass
, which inherits from the base (or root) class,NSObject
. (A root class is one that all other classes directly or indirectly inherit from.) The class declaration begins with the @interface
compiler directive and ends with the @end
directive. Following the class name (and separated from it by a colon) is the name of the parent class. In Objective-C, a class can have only one parent.
下图显示了MyClass类的声明语法, 该类继承字基类(根)NSObject. (根类是所有其他类直接或间接从它这继承的类) 类声明以 @interface编译器指令开始,以 @end指令结束。类名后面(以冒号分隔)的是父类。 Objective-C中,一个类只能有一个父类。
![A class declaration](https://developer.apple.com/library/mac/referencelibrary/GettingStarted/RoadMapOSX/books/WriteObjective-CCode/Art/class_decl_2x.png)
You write declarations of properties and methods between the @interface
and @end
directives. These declarations form the public interface of the class. (Declared properties are described in “Declared Properties and Accessor Methods.”) A semicolon marks the end of each property and method declaration. If the class has custom functions, constants, or data types associated with its public interface, put their declarations outside the @interface
. . . @end
block.
你可以在@interface 和 @end之间 编写 属性(properties) 和方法(methods)的声明。这些声明组成类的公共接口。 (声明属性--Declared properties 在 “Declared Properties and Accessor Methods.” 描述 ) 分号 标记每个属性和方法声明的结束。 如果类有自定义跟它的公共接口相关的 函数,常量 或者数据类型,把它们的声明放到@interface 和 @end外面。
The syntax for a class implementation is similar. It begins with the @implementation
compiler directive (followed by the name of the class) and ends with the @end
directive. Method implementations go in between. (Function implementations should go outside the @implementation…@end
block.) An implementation should always import its interface file as one of the first lines of code.
一个类实现的方法也很类似。它由 @implementation 编译器指令开始(后面跟着类名),由@end指令结束。 方法的实现在它们中间。 (函数实现应该在@implementation ... @end块的外面) 一个实现应该总是在代码开始处导入它的接口文件。
#import "MyClass.h" |
@implementation MyClass |
- (id)initWithString:(NSString *)aName |
{ |
// code goes here |
} |
+ (MyClass *)myClassWithString:(NSString *)aName |
{ |
// code goes here |
} |
@end |
Objective-C supports dynamic typing for variables containing objects, but it also supports static typing. Statically typed variables include the class name in the variable type declaration. Dynamically typed variables use the type id
for the object instead. You find dynamically typed variables used in certain situations. For example, a collection object such as an array (where the exact types of the contained objects may be unknown) might use dynamically typed variables. Such variables provide tremendous flexibility and allow for greater dynamism in Objective-C programs.
Objective-C 变量(variables)支持包含对象的动态类型, 同时也支持静态类型。 静态类型变量(Statically typed variables) 在变量类型声明里包含其类名。动态类型变量(Dynamically typed variables) 则给对象使用类型符 --id -- 取代类名。 你会发现动态类型变量在一些特性情况下使用,举个例子, 一个集合对象(collection object)比如 数组(可能不知道包含对象的具体类型)可能使用动态类型变量。这种变量提供了极大的灵活性,并在Objective-C 程序里允许有更大的动态性(greater dynamism)。
This example shows statically and dynamically typed variable declarations:
以下例子显示了 静态 和动态 类型变量的声明:
MyClass *myObject1; // Static typing |
id myObject2; // Dynamic typing |
Notice the asterisk (*
) in the first declaration. In Objective-C, object references must always be pointers. If this requirement doesn’t make complete sense to you, don’t worry—you don’t have to be an expert with pointers to be able to start programming with Objective-C. You just have to remember to put the *
in front of the variable names for statically typed object declarations. The id
type implies a pointer.
注意在以第一声明里的星号(*)。 在Objective-C里, 对象引用必须都是按指针引用。 如果你还不能理解指针,别担心--你不一定要称为指针的专家才能开始学习Objective-C 编程。 你只需要记住静态类型对象声明时在变量名之前放一个*号。id 类型表明是一个指针。
Methods and Messaging(方法和消息)
If you’re new to object-oriented programming, it might help to think of a method as a function that is scoped to a specific object. By sending a message to—or messaging—an object, you call a method of that object. There are two kinds of methods in Objective-C: instance methods and class methods.
如果你在面向对象编程方面是个新手,把一个方法(method) 想象成作用域是特定对象的一个函数可能会对你有帮助。给一个对象发送一个消息--messaging--,我们把这个称为是该对象的方法。 Objective-C里有2种方法: 实例方法 和 类方法。
-
An instance method is a method whose execution is scoped to a particular instance of the class. In other words, before you call an instance method, you must first create an instance of the class. Instance methods are the most common type of method.
实例方法的执行范围是一个类的特定实例。换句话说,在你调用一个实例方法之前,你必须先创建一个类的实例。 实例方法是最常见的方法类型。
-
A class method is a method whose execution is scoped to the method’s class. It does not require an instance of an object to be the receiver of a message.
类方法的执行范围是方法的类。它不要求一个对象实例作为一个消息的接受者(receiver of message)。
The declaration of a method consists of the method type identifier, a return type, one or more signature keywords, and the parameter type and name information. Here’s the declaration of the insertObject:atIndex:
instance method.
一个方法的声明由 方法类型标识符(Method type identifier), 一个返回值类型(Return type), 一个或多个签名关键字(Method signature keywords) 以及 参数类型(Parameter types) 和 参数名(Parameter name)信息组成。
![Method declaration syntax](https://developer.apple.com/library/mac/referencelibrary/GettingStarted/RoadMapOSX/books/WriteObjective-CCode/Art/method_decl_2x.png)
For instance methods, the declaration is preceded by a minus sign (-
); for class methods, the corresponding indicator is a plus sign (+
). “Class Methods”, below, describes class methods in greater detail.
实例方法,声明时前面加一个减号符(-), 类方法则在前面加一个加号(+)。下面的"Class Methods",介绍了类方法的更多细节。
A method’s actual name (insertObject:atIndex:
) is a concatenation of all of the signature keywords, including colon characters. The colon characters declare the presence of a parameter. In the above example, the method takes two parameters. If a method has no parameters, you omit the colon after the first (and only) signature keyword.
一个方法的真实名字(insertObject:atIndex:)是所有签名关键字的一个串联(concatenation),包括冒号(:)。冒号字符表明一个参数的存在。 在上面的例子中, 方法带有2个参数。 如果一个方法没有参数,你也应该在第一个(也只有一个)签名关键字后面添加一个冒号。
When you want to call a method, you do so by sending a message to the object that implements the method—or, in other words, by messaging that object. (Although the phrase "sending a message" is commonly used as a synonym for "calling a method,“ the Objective-C runtime does the actual sending.) A message is the method name along with the parameter information the method needs (properly conforming to type). All messages you send to an object are dispatched dynamically, thus facilitating the polymorphic behavior of Objective-C classes. (Polymorphism refers to the ability of different types of objects to respond to the same message.) Sometimes the method invoked is implemented by a superclass of the class of the object receiving the message.
当你想要调用一个方法时, 你通过给实现该方法的对象传送一个消息来实现。---换句话说,就是给那个对象messaging。(尽管短语"sending a message--发送一个消息" 是 "calling a method--调用一个方法"的代名词(synonym), 实际执行传送的是Objective-C的运行(runtime))一个消息就是方法名以及该方法需要的参数信息(正确地符合类型). 所有你发送给一个对象的信息会被动态发派(dispatched dynamically),从而促进Objective-C类的多态行为(polymorphic behavior)。
To dispatch a message, the runtime requires a message expression. A message expression encloses with brackets ([
and ]
) the message itself (along with any required parameters) and, just inside the leftmost bracket, the object receiving the message. For example, to send the insertObject:atIndex:
message to an object held by the myArray
variable, you would use the following syntax:
要法派一个消息,runtime 要求一个消息表达式。 一个 消息表达式(message expression) 由方括号([ 和 ])包围,包括消息自身(以及任何需要的参数), 靠近最左边的方括号处是接收消息的对象。 举个例子,给拥有myArray变量的对象 发送 insertObject:atIndex: 消息,你应该使用以下语法:
[myArray insertObject:anObject atIndex:0]; |
To avoid declaring numerous local variables to store temporary results, Objective-C lets you nest message expressions. The return value from each nested expression is used as a parameter or as the receiving object of another message. For example, you could replace any of the variables used in the previous example with messages to retrieve the values. Thus, if you had another object called myAppObject
that had methods for accessing the array object and the object to insert into the array, you could write the preceding example to look something like the following:
为了避免声明众多的局部变量(local variables)来存储临时结果,Objective-C 允许你嵌套(nest)消息表达式。每个从嵌套表达式返回的结果值将左右一个参数,或者作为另一个消息的接收对象(receiving object)。 举个例子, 你可以用消息(messages)替代前面例子中的任何变量来检索(retrieve)值。因而,如果你有另一个叫做myAppObject的对象,而该对象有访问数组对象的方法,该对象想往数组插入对象,你可以把前面的例子修改为以下语句:
[[myAppObject theArray] insertObject:[myAppObject objectToInsert] atIndex:0]; |
Objective-C also provides a dot-notation syntax for invoking accessor methods. Accessor methods get and set the state of an object, and thus are key to encapsulation, which is an important feature of all objects. Objects hide, orencapsulate, their state and present an interface common to all instances for accessing that state. Using dot-notation syntax, you could rewrite the previous example as:
Objective-C 也提供了一种 点运算符 语法,用来调用存取方法。 存取方法(Accessor methods)用来get 和 set 一个对象的状态,是封装(encapsulation)的关键。 封装是所有对象的一个重要特性。 隐藏对象即封装 它们的状态,然后给所有实例对象提供一个可以访问那个状态的通用接口。用点运算符语法,你可以重写上面的例子:
[myAppObject.theArray insertObject:myAppObject.objectToInsert atIndex:0]; |
You can also use dot-notation syntax for assignment:
你同样可以用点运算符语法(dot-notation)来赋值(assignment):
myAppObject.theArray = aNewArray; |
This syntax is simply a different way to write [myAppObject setTheArray:aNewArray];
. You cannot use a reference to a dynamically typed object (type of id
) in a dot-notation expression.
该语法跟[myAppObject setTheArray:aNewArray]; 稍微有点不同。你不能用点运算符表达式引用一个动态类型对象(id 类型)。
You have used dot-notation syntax already for assigning to a variable in Your First Mac App:
你在Your First Mac App教程里已经使用过点运算符语法:
float volume = self.track.volume; |
Class Methods
Although the preceding examples sent messages to an instance of a class, you can also send messages to the class itself. (A class is an object of type Class
created by the runtime.) When messaging a class, the method you specify must be defined as a class method instead of an instance method. Class methods are a feature similar to static class methods in C++.
尽管前面的例子都是向一个类的实例发送消息,但是你也同样可以给类自身发送消息。(类是一个由runtime创建的类型为Class 的对象)当你向一个类发送消息时,你指定的方法必须被定义为是一个类方法,而不是一个实例方法。
You often use class methods as factory methods to create new instances of the class or for accessing some piece of shared information associated with the class. The syntax for a class method declaration is identical to that of an instance method except that you use a plus (+
) sign instead of a minus sign for the method type identifier.
你常常使用类方法作为工厂方法(factory methods)用来创建类的新实例 或者 访问一些跟类相关的共享信息的片段。类方法声明的语法跟实例方法声明的方法相同,除了你需要把方法类型标识符(method type identifier)用加号(+)代替 减号(-)。
The following example illustrates how you use a class method as a factory method for a class. In this case, the array
method is a class method on the NSArray
class—and inherited by NSMutableArray
—that allocates and initializes a new instance of the class and returns it to your code.
以下例子演示了一个类如何使用一个类方法,并把它作为一个工厂方法。
NSMutableArray *myArray = nil; // nil is essentially the same as NULL |
// Create a new array and assign it to the myArray variable. |
myArray = [NSMutableArray array]; |
Declared Properties and Accessor Methods
声明特性和存取方法
A property in the general sense is some data encapsulated or stored by an object. It is either an attribute—such as a name or a color—or a relationship to one or more other objects. The class of an object defines an interface that enables users of its objects to get and set the values of encapsulated properties. The methods that perform these actions are called accessor methods.
基本上说,一个特性就是一些被对象封装或存储的数据。它可以是一个属性(attribute)--比如 一个名字 或 一个颜色 -- 也可以是一个或多个其他对象之间的关系。 对象的类定义了一个接口,该接口允许它的那些对象用户get 和 set 这些封装特性(encapsulated properties)的值。
There are two types of accessor methods, and each method must conform to a naming convention. A “getter” accessor method, which returns the value of a property, has the same name as the property. A "setter” accessor method, which sets a new value for a property, has the form set
PropertyName:
, where the first letter of the property name is capitalized. Properly named accessor methods are a critical element of several technologies of the Cocoa and Cocoa Touch frameworks, including key-value coding (KVC), which is a mechanism for accessing an object’s properties indirectly through their names.
有2中类型的存取方法,每种方法都必须符合命名规则(naming convention)。"getter"存取方法跟特性(property)同名,它返回一个特性的值(value of property)。"setter" 方法,给特性(property)设置一个新值。 它符合setPropertyName:格式,特性名的首字符必须大写。正确命名存储器方法(accessor methods) 是 Cocoa 和 Cocoa Touch 框架几种技术的一个关键要素,包括 键-值 编码(KVC)---一种通过它们的名字间接访问一个对象的特性的机制。
Objective-C offers declared properties as a notational convenience for the declaration and implementation of accessor methods. In Your First Mac App you declared the volume
property:
Objective-C 提供声明的特性(declared properties)作为一种声明和存取方法实现(implementation of accessor methods)的符号上的便利。在 Your First Mac App 教程里申明的 volume 特性:
@property (assign) float volume; |
Declared properties eliminate the need to implement a getter and setter method for each property exposed in the class. Instead, you specify the behavior you want using the property declaration. The compiler can then create—orsynthesize—actual getter and setter methods based on that declaration. Declared properties reduce the amount of boilerplate code you have to write and, as a result, make your code much cleaner and less error prone. Use declared properties or accessor methods to get and set items of an object’s state.
声明的特性(Declared properties)解除了为每个裸露(exposed)在类中的特性实现一个getter 和 setter方法。取而代之,你需要 使用特性声明指定你想要的行为。 然后编译器会在特性声明的基础上创建--或 合成(synthesize)--真正的getter 和 setter 方法。声明的特性减少了你不得不写的代码总量, 所以,它使你的代码变得更加清晰,减少错误发生。 使用 声明的特性(declared properties) 或 存取方法(accessor methods) 来get 和 set 一个对象状态的项(items)。
You include property declarations with the method declarations in your class interface. You declare public properties in the class header files; you declare private properties in a class extension in the source file. (See “Protocols and Categories” for a short description of class extensions along with an example.) Properties of controller objects such as delegates and view controllers should typically be private.
你在你的类接口里包含了特性声明 和 方法声明。 你在类头文件里声明那些公共特性;在资源文件(source file)的类的扩展(class extension)里声明似有特性(private properties)。(“Protocols and Categories” 简单描述了类的扩展并举了一个例子).
The basic declaration for a property uses the @property
compiler directive, followed by the type information and name of the property. You can also configure the property with custom options, which define how the accessor methods behave, whether the property is a weak reference, and whether it is read-only. The options are in parentheses following the @property
directive.
一个特性的基本声明用@property编译器指令, 后面跟着类型信息 和 特性名。 你也可以设置特性的自定义选项(custom options),选项定义存取方法如何工作(behave), 该特性是否是一个弱引用(weak reference), 是否是只读的(read-only)。 @property 指令后面 括号里面的是选项。
The following lines of code illustrate a few more property declarations:
以下几行代码演示了一些特性声明:
@property (copy) MyModelObject *theObject; // Copy the object during assignment. |
@property (readonly) NSView *rootView; // Declare only a getter method. |
@property (weak) id delegate; // Declare delegate as a weak reference |
The compiler automatically synthesizes declared properties. In synthesizing a property, it creates accessor methods for it as well as a private instance variable that “backs” the property. The instance variable has the same name as the property but with an underscore prefix (_
). Your app should directly access an instance variable (instead of its property) only in methods for object initialization and deallocation.
编译器会自动生成(synthesizes)声明的特性(declared properties)。 生成一个特性时, 它为特性创建存取方法的同时也创建了特性背后的似有实例变量(private instance variable). 实例变量跟特性同名,但是有一个下划线(_)前缀。 只有在对象初始化(initialization)和释放(deallocation)的方法中,你的应用应该才直接访问一个实例变量(而不是它的特性)。
If you want a different name for an instance variable, you can bypass autosynthesis and explicitly synthesize a property. Use the @synthesize
compiler directive in the class implementation to ask the compiler to generate the accessor methods along with the specially named instance variable. For example:
如果想给一个实例变量一个不同的名字, 你可以放弃(bypass)自动生成(autosynthesis), 明确合成一个特性。用类实现里的@synthesize 编译器指令,要求编译器根据特殊名字的实例变量生成存取方法。
@synthesize enabled = _isEnabled; |
Incidentally, when you declare a property you can specify custom names for the accessor methods, typically to make the getter methods of Boolean properties follow a conventional form, as shown here:
顺便说一句,当你声明一个特性时,你可以为存取方法指定自定义名字, 通常是为了使布尔属性(Boolean properties)的getter方法遵循传统的形式,如下所示:
@property (assign, getter=isEnabled) BOOL enabled; // Assign new value, change name of getter method |
Blocks(块)
Blocks are objects that encapsulate a unit of work—that is, a segment of code—that can be executed at any time. They are essentially portable and anonymous functions that one can pass in as parameters of methods and functions or that can be returned from methods and functions. Blocks themselves have a typed parameter list and may have an inferred or a declared return type. You can also assign a block to a variable and then call it just as you would a function.
块(Blocks)是用来封装一工作单元的对象---就是,一个代码段--它们能在任何时候被执行。 它们基本上是轻便的(portable),匿名的函数,可以被作为方法或函数的参数传入, 也可以被从方法或函数返回。块本身有一个类型参数列表(typed parameter list), 也可能有一个推断的(inferred)或声明的(declared)返回类型。
A caret (^
) is used as a syntactic marker for blocks. There are other, familiar syntactic conventions for parameters, return values, and body of the block (that is, the executed code). The following figure explicates the syntax, specifically when assigning a block to a variable.
(^)被用作块的语法标记符。 除此之外,还有其他一些拥有熟悉的语法规则的参数, 返回值, 以及块的正文(body)--也就是执行代码。 下图清晰的表明了块的语法,特别是当分配一个块给一个变量时。
![image: ../Art/blocks.png](https://developer.apple.com/library/mac/referencelibrary/GettingStarted/RoadMapOSX/books/WriteObjective-CCode/Art/blocks.png)
You can then call the block variable as if it were a function:
然后你就可以把块变量当函数一样调用。
int result = myBlock(4); // result is 28 |
A block shares data in the local lexical scope. This characteristic of blocks is useful because if you implement a method and that method defines a block, the block has access to the local variables and parameters of the method (including stack variables) as well as to functions and global variables, including instance variables. This access is read-only, but if a variable is declared with the __block
modifier, its value can be changed within the block. Even after the method or function enclosing a block has returned and its local scope has been destroyed, the local variables persist as part of the block object as long as there is a reference to the block.
块在局部词法作用域内分享数据。 该类的特性很有用,因为如果你实现一个方法,而那个方法定义了一个块,这个块就能访问局部变量和方法的参数(包括堆栈变量),同时能访问函数和全局变量,包括实例变量。甚至于在隐藏了该块的方法或者函数返回之后,并且它的局部作用域(local scope)已经被摧毁(destroyed)的情况下,只要还存在一个对块的引用,局部变量仍坚持自己是块对象的一部分。
As method or function parameters, blocks can serve as a callback. When invoked, the method or function performs some work and, at the appropriate moments, calls back to the invoking code—via the block—to request additional information or to obtain program-specific behavior from it. Blocks enable the caller to provide the callback code at the point of invocation. Instead of packaging the required data in a “context” structure, blocks capture data from the same lexical scope as the host method or function. Because the block code does not have to be implemented in a separate method or function, your implementation code can be simpler and easier to understand.
作为方法或函数的参数,块可以像一个回调函数(callback)工作。 当被调用时, 方法或函数执行一些工作,在适当的时刻,回调调用代码-- 通过(via)块--请求额外的信息 或者 从它那获取程序特定(program-specific)的行为。块允许调用者(caller)在调用点(the point of invocation)提供回调代码。 代替把需要的代码打包进一个"context"结构,块从同一个词法作用域(same lexical scope)内像主方法或函数那样捕捉数据。 因为块代码不必要在一个单独的方法或函数内实现,所有你的实现代码可以更简单,更易懂。
Objective-C frameworks have many methods with block parameters. For example, the NSNotificationCenter
class of the Foundation framework declares the following method, which has a block parameter:
Objective-C框架 有很多方法带有块参数。比如, Foundation 框架中的 NSNotificationCenter类 定义了以下方法,该方法有块参数:
- (id)addObserverForName:(NSString *)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block |
This method adds an observer to the notification center (notifications are discussed in Streamline Your App with Design Patterns). When a notification of the specified name is posted, the block is invoked to handle the notification.
该方法给notification center(通知中心)添加一个observer(观察者)。(notifications--通知在Streamline Your App with Design Patterns 里讨论)。当一个有特定名字的通知(notification)被推送(posted)时, 块被调用来处理该通知(notification)。
opQ = [[NSOperationQueue alloc] init]; |
[[NSNotificationCenter defaultCenter] addObserverForName:@"CustomOperationCompleted" |
object:nil queue:opQ |
usingBlock:^(NSNotification *notif) { |
// handle the notification |
}]; |
Protocols and Categories
协议和类别
A protocol declares methods that can be implemented by any class, even if those classes implementing the protocol don’t have a common superclass. Protocol methods define behavior that is independent of any particular class. Protocols simply define an interface that other classes are responsible for implementing. When your class implements the methods of a protocol, your class is said to conform to that protocol.
协议(protocal)声明了能被任何类实现的方法, 即使这些实现协议的类没有一个共同的超类(common superclass)。协议方法定义了独立于任何特定类的行为(behavior)。协议只是简单定义了别的类负责实现的一个接口。 当你的类实现了一个协议的方法,则称该类符合该协议。
From a practical perspective, a protocol defines a list of methods that establishes a contract between objects without requiring them to be instances of any specific class. This contract enables communication between those objects. One object wants to tell another object about the events it’s encountering, or perhaps it wants to ask for advice about those events.
从实践角度说,一个协议定义了一系列方法。这些方法建立了对象之间的一个合同,而且这些对象不一定成为任何特定类的实例。该合同能让那些对象之间进行通信。一个对象想告诉另一个对象关于它遭遇(encountering)的事件(events), 或者也许它想就那些事件像另一个对象咨询一些建议(ask for advice)。
The UIApplication
class implements the required behavior of an application. Instead of forcing you to subclassUIApplication
to receive simple notifications about the current state of the application, the UIApplication
class delivers those notifications by calling specific methods of its assigned delegate object. An object that implements the methods of the UIApplicationDelegate
protocol can receive those notifications and provide an appropriate response.
UIApplication 类 实现了一个应用程序所要求的行为。 UIApplication 类只需通过调用其分配的委托对象(its assigned delegate object)的特定方法来传递那些通知(notifications), 而不需要强制称为UIApplication类的子类去接收关于应用程序当前状态的简单通知. 那个实现UIApplicationDelegate协议方法的对象能接收那些通知,并提供一个适当的反馈(appropriate response)。
You specify in the interface block that your class conforms to, or adopts, a protocol by putting the name of the protocol in angle brackets (<...>
) after the name of the class from which it inherits. In Your First Mac App, adoption of theNSApplicationDelegate
protocol is specified in the following line:
你可以在接口块(interface block) 里通过在尖括号(<...>)里放入协议名称来指定你的类符合,或采用,一个协议。
@interface TrackMixAppDelegate : NSObject <NSApplicationDelegate> |
You do not have to declare the protocol methods you implement.
你不必声明你实现的协议方法。
The declaration of a protocol looks similar to that of a class interface, with the exceptions that protocols do not have a parent class and they do not define instance variables (although they can declare properties). The following example shows a simple protocol declaration with one method:
一个协议的声明跟一个类接口的声明很类似,除了协议没有一个父类,而且协议也不定义实例变量(尽管它们能声明特性)。以下例程显示了一个简单协议的声明,该协议有一个方法:
@protocol MyProtocol |
- (void)myProtocolMethod; |
@end |
For many delegate protocols, adopting a protocol is simply a matter of implementing the methods defined by that protocol. There are some protocols that require you to state explicitly that you support the protocol, and protocols can specify both required and optional methods.
对于很多委托协议(delegate protocols), 采用一个协议,实现那个协议所定义的方法是一件简单的事。有一些协议要求你明确的声明你支持该协议, 而且协议能同时指定必要的(required)和可选的(optional)方法。
When you begin exploring the header files of the Objective-C frameworks, you’ll soon encounter a line similar to this one:
当你开始探索Objective-C框架的头文件,你将很快遇见跟下面相似的语句:
@interface NSDate (NSDateCreation) |
This line declares a category through the syntactical convention of enclosing the name of the category in parentheses. Acategory is a feature of the Objective-C language that enables you to extend the interface of a class without having to subclass it. The methods in the category become part of the class type (within the scope of your program) and are inherited by all the class’s subclasses. You can send a message to any instance of the class (or its subclasses) to invoke a method defined in the category.
该行通过把类别名称放在括号里面的语法规则,声明了一个类别(category)。 类别(category)是Objective-C语言的一个特性,它能让你扩展一个类的接口,而不需要称为该类的子类。 类别(category)里的方法称为class类型的一部分(在你的程序范围内),并且被所有类的子类所继承。 你可以个任何类(或子类)的实例发一个消息,来调用类别里的方法。
You can use categories as a means for grouping related method declarations within a header file. You can even put different category declarations in different header files. The frameworks use these techniques throughout their header files for clarity.
你可以把类别作为 把一个头文件里的相关方法声明归为一组的一种手段。 你甚至可以把不同的类别声明放在不同的头文件里。 框架在他们的整个头文件里都使用这些技术,以增加清晰度。
You can also use an anonymous category known as a class extension to declare private properties and private methods in the implementation (.m
) file. A class extension looks like a category except there is no text between the parentheses. For example, the following shows a typical class extension:
你也可以在实现文件(.m)里使用一个匿名类别,被称为一个类扩展,来声明似有特性 和似有方法。 类扩展(class extension)看起来像一个类别,除了在括号里面没有任何文字。 比如,下面显示了一个典型的类扩展:
@interface TrackMixAppDelegate () |
@property (weak) IBOutlet NSWindow *window; |
@property (assign) IBOutlet NSTextField *nameField; |
@property (strong) MyDataObject *data; |
@end |
Defined Types and Coding Strategies
定义类型 和 编码策略
Objective-C has several terms that you should not use as the names of variables because they are reserved for special purposes. Some of these terms are compiler directives that are prefixed with an at sign (@
, for example, @interface
and @end
). Other reserved terms are defined types and the literals that go with those types. Objective-C uses a number of defined types and literals that you won’t find in ANSI C. In some cases, these types and literals replace their ANSI C counterparts. The following table describes a few of the important ones, including the allowable literals for each type:
Objective-C有一些术语(terms)不能被用来作为你的变量名,因为他们被保留用语特殊用途。 其中一些术语是编译器指令,它们有@开头(比如,@interface , @end)。其余的保留术语(reserved terms)被用作 类型 和 跟那些类型一起使用的文字(literals)。 Obejective-C 使用了很多你在ANSI C里找不到的定义类型(defined types) 和 文字(literals)。 在某些情况下,这些类型和文本将替代ANSI C里的相关保留字或文本。 下表描述了其中重要的一小部分,包括每个类型的允许文本(allowable literals)。
Type |
Description and literal(描述 和 文字) |
---|---|
|
The dynamic object type. The negative literal for both dynamically and statically typed objects is |
|
The dynamic class type. Its negative literal is |
|
The data type ( |
|
A Boolean type. The literal values are |
You often use these defined types and literals in error-checking and control-flow code. In your program’s control-flow statements, you can test the appropriate literal to determine how to proceed. For example:
你常常在错误检测(error-checking)和控制流(control-flow)代码中使用这些定义类型(defined types)和文字(literals)。在程序的控制流语句里,你可以测试适当的文字来觉得如何继续。 比如:
NSDate *dateOfHire = [employee dateOfHire]; |
if (dateOfHire != nil) { |
// handle this case |
} |
To paraphrase this code, if the object representing the date of hire is not nil
—in other words, it is a valid object—then the logic proceeds in a certain direction. Here’s a shorthand way of doing the same branching:
该代码说明, 如果 dateOfHire 不是 nil --换句话说就是 这是一个有效的对象--,则逻辑上确定一个方向继续。这里有一种更简便的写法:
NSDate *dateOfHire = [employee dateOfHire]; |
if (dateOfHire) { |
// handle this case |
} |
You can even reduce these lines of code further (assuming you don’t need a reference to the dateOfHire
object):
你还可以进一步缩减这些代码(假设你不需要引用dateOfHire 对象)
if ([employee dateOfHire]) { |
// handle this case |
} |
You handle Boolean values in much the same way. In this example, the isEqual:
method returns a Boolean value:
你可以用差不多相同的方式处理布尔值。 以下例子中isEqual: 方法返回一个布尔值:
BOOL equal = [objectA isEqual:objectB]; |
if (equal == YES) { |
// handle this case |
} |
You can shorten this code in the same way you can for the code that tests for the absence or presence of nil
.
你可以用同样的方式缩减该代码,测试nil值的存在或不存在。
In Objective-C you can send a message to nil
with no ill effects. Indeed there is no effect at all, except that the runtime returns nil
if the method is supposed to return an object. Return values from messages sent to nil
are guaranteed to work as long as what is returned is typed as an object.
在 Obejective-C中, 你可以给nil 发送一个消息,不会发生错误效果。 事实上一点效果也没有,除了如果方法支持返回一个对象,runtime就返回nil. 从发送给nil对象返回的值保证能工作,只要它返回的是一个对象。
Two other important reserved terms in Objective-C are self
and super
. The first term, self
, is a local variable that you can use within a message implementation to refer to the current object; it is equivalent to this
in C++. You can substitute the reserved word super
for self
, but only as the receiver in a message expression. If you send a message toself
, the runtime first looks for the method implementation in the current object’s class; if it can’t find the method there, it looks for it in its superclass (and so on). If you send a message to super
, the runtime first looks for the method implementation in the superclass.
Objective-C 里,其它2个重要的保留字(reserved terms)是self 和 suoer。 第一个保留字,self, 是一个局部变量,你可以在一个消息实现里用它引用当前对象; 它相当于C++里的this。你可以用self替代super, 但只作为一个消息表达式的接受者。 如果你给self发送了一个消息,runtime 首先在当前对象的类里查找方法实现; 如果在这里找不到方法,它就在它的超类里查找(and so on)。如果你给super发送了一个消息,runtime 首先在超类里查找方法实现。
The primary uses of both self
and super
have to do with sending messages. You send a message to self
when the method to invoke is implemented by the class of self
. For example:
self 和 super 的主要用途就是跟发送消息一个使用。 当方法调用是由self 类实现时,你发送一个消息给self. 比如:
[self doSomeWork]; |
self
is also used in dot notation to invoke the accessor method synthesized by a declared property. For example:
self 也能在点运算符(.)格式里使用,它用来调用被一个声明的特性(declared property)合成的存取方法. 比如:
NSString *theName = self.name; |
You often send messages to super
in overrides (that is, reimplementations) of methods inherited from a superclass. In this case, the method invoked has the same signature as the method overridden.