这几天把Programming with Objective-C再看了一边,发现有很多以前不明确的地方。现在把一些重要的点记下来,巩固学习效果。
1.Objective-C Classes Are also Objects(OC类也是对象)
In Objective-C, a class is itself an object with an opaque type called Class. Classes can’t have properties defined using the declaration syntax shown earlier for instances, but they can receive messages.
The typical use for a class method is as a factory method, which is an alternative to the object allocation and initialization procedure described in Objects Are Created Dynamically (page 34).
类也是特殊的对象,典型的用法是类中的方法被称作工厂方法。
2.Use Pointers to Keep Track of Objects(使用指针记录对象)
Objects normally have a longer life than the simple scope of a method call. In particular, an object often needs to stay alive longer than the original variable that was created to keep track of it, so an object’s memory is allocated and deallocated dynamically.
If you’re used to using terms like the stack and the heap,a local variable is allocated on the stack, while objects are allocated on the heap.
这里针对 local variable(本地变量)和object(对象)的不同点,介绍了两套解释的术语。后面一种比较熟悉,本地变量存放在stack(栈)中,对象存放在heap(堆)中。
3.Objects Are Created Dynamically(对象是被动态创建的)
The NSObject root class provides a class method, alloc, which handles this process for you:
?+ (id)alloc;
Notice that the return type of this method is id. This is a special keyword used in Objective-C to mean “some kind of object.” It is a pointer to an object, like (NSObject *), but is special in that it doesn’t use an asterisk.
The alloc method has one other important task, which is to clear out the memory allocated for the object’s properties by setting them to zero. This avoids the usual problem of memory containing garbage from whatever was stored before, but is not enough to initialize an object completely.
创建对象时,需要调用alloc方法,返回的类型是id,id是一个只想对象的指针,它表示“某一类对象”,但比较特殊的是不需要加星号。
alloc方法另一个作用是讲对象中的属性归零,这避免了内存垃圾产生的影响。
You need to combine a call to alloc with a call to init, another NSObject method:
- (id)init;
The init method is used by a class to make sure its properties have suitable initial values at creation, and is covered in more detail in the next chapter.
init方法用来确保所有参数都被初始化。
4.Objective-C Is a Dynamic Language(OC是一门动态语言)
Because of Objective-C’s dynamic nature, it doesn’t matter what specific class type you use for that pointer—the correct method will always be called on the relevant object when you send it a message.
id someObject = @"Hello, World!";
[someObject removeAllObjects];
OC是动态语言,这里它举了一个例子,someObject是NSString型对象,没有removeAllObjects方法,但编译器没有报错,只会在运行时抛出异常。这说明OC只在运行时确定方法的调用。
5.Most Properties Are Backed by Instance Variables(大部分属性基于实例变量)
For a property called firstName, for example, the synthesized instance variable will be called _firstName.
In general, you should use accessor methods or dot syntax for property access even if you’re accessing an
object’s properties from within its own implementation, in which case you should use self:
The exception to this rule is when writing initialization, deallocation or custom accessor methods, as described later in this section.
比如属性名为firstName,那么综合的实例变量名为_firstName
一般的,通过self.语法获取属性。
也有例外情况,当我们初始化,销毁,或自定义getter/setter方法时,需要直接访问实例变量,如_firstName。
6.Designated Initializer(指定初始化器)
这部分还没有深入学习。
7.Properties Are Atomic by Default(属性默认是原子的)
Propertyatomicityisnotsynonymouswithanobject’sthreadsafety.
Consider an XYZPerson object in which both a person’s first and last names are changed using atomic accessors from one thread. If another thread accesses both names at the same time, the atomic getter methods will return complete strings (without crashing), but there’s no guarantee that those values will be the right names relative to each other. If the first name is accessed before the change, but the last name is accessed after the change, you’ll end up with an inconsistent, mismatched pair of names.
属性设置为atomic不能保证线程安全,这里举了一个XYZPerson对象的例子。
8.Avoid Strong Reference Cycles(避免循环引用)
A common scenario is that the table view has a reference to its delegate and the delegate has a reference back to the table view, as shown in Figure 3-7 (page 59).
举了一个tableview和delegate的例子说明为什么会发生循环引用。
The way to solve this problem is to substitute one of the strong references for a weak reference. A weak reference does not imply ownership or responsibility between two objects, and does not keep an object alive.
为了避免循环应用,可以使用weak修饰符,如
@property (weak) id delegate;
NSObject * __weak weakVariable;
9.向weak修饰的对象发送消息的标准方法
NSObject *cachedObject = self.someWeakProperty; //1
if (cachedObject) { //2
[someObject doSomethingImportantWith:cachedObject]; //3
} //4
cachedObject = nil;
10.Copy Properties Maintain Their Own Copies(拷贝类型属性维护自己的副本)
通过例子说明为什么NSString一般使用copy修饰符。
11.Categories and Class Extension(分类和类扩展)
Categories can be used to declare either instance methods or class methods but are not usually suitable for declaring additional properties.
分类可以什么类方法和实例方法,但不能声明属性。
Unlike regular categories, a class extension can add its own properties and instance variables to a class.
类扩展可以增加属性和实例变量。
属性:
@interface XYZPerson ()
@property (readwrite) NSString *uniqueIdentifier;
@end
实例变量:
@interface XYZPerson () {
id _someCustomInstanceVariable;
}
12.Check that Optional Methods Are Implemented at Runtime(运行时检查可选方法是否被实现)
If a method in a protocol is marked as optional, you must check whether an object implements that method before attempting to call it.
NSString *thisSegmentTitle;
if ([self.dataSource respondsToSelector:@selector(titleForSegmentAtIndex:)])
{
thisSegmentTitle = [self.dataSource titleForSegmentAtIndex:index];
}
当协议中有可选方法时,需要使用respondsToSelector:方法判断是否实现了可选方法。
13.Objects Use Properties to Keep Track of Blocks(block作为属性存到对象中)
property (copy) void (^blockProperty)(void);
You should specify copy as the property attribute, because a block needs to be copied to keep track of its captured state outside of the original scope. This isn’t something you need to worry about when using Automatic Reference Counting, as it will happen automatically, but it’s best practice for the property attribute to show the resultant behavior. For more information, see Blocks Programming Topics .
解释了为什么block属性要用copy修饰。
14.Use __block Variables to Share Storage(使用__block修饰符共享内存区域)
If you need to be able to change the value of a captured variable from within a block, you can use the __block storage type modifier on the original variable declaration.
__block int anInteger = 42;
void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger);
};
anInteger = 84;
testBlock();
block在捕获作用域外的变量时,默认copy变量的值。如果要改变修改变量,需要用__block修饰。
15.Avoid Strong Reference Cycles when Capturing self(block中调用self时避免循环引用)
- (void)configureBlock {
XYZBlockKeeper * __weak weakSelf = self;
self.block = ^{
[weakSelf doSomething]; // capture the weak reference
} }
block中如果向self对象发送消息,会发生循环引用,给出了标准的解决方法。