block
block分stack/heap/global:block通常是其创建时所在作用域的栈变量,出了作用域这块内存可能被释放可能不释放;通过copy后block变成堆变量,使用引用计数;未引用任何外部变量和参数的block是全局变量,copy无用也不dealloc。
block的参数列表为空时是接受_可变参数_,
void (^block)();
和void (^block)(void);
不同。参见:ObjC非主流代码技巧
block中避免循环引用self:先在block外:
然后在block中:1
__weak __typeof(self) weakSelf = self;
注意:block中的_ivar会隐式引用self(即self->_ivar),要改成weakSelf->_ivar或weakSelf.ivar。更优雅的方法是使用ReactiveCocoa的libextobjc中的1
__strong __typeof(weakSelf) strongSelf = weakSelf;
@weakify(self)
和@strongify(self)
。在block中要小心使用
NSAssert
,因为NSAssert宏展开中使用了self很可能导致循环引用,可用NSCassert
。
selector
performSelector延迟调用可用
dispatch_after()
替代,如:1
2
3
4
5// [self performSelector:@selector(doSomething) withObject:nil afterDelay:5.0];
dispatch_time time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC));
dispatch_after(time, dispatch_get_main_queue(), ^(void){
[self doSomething];
});performSelector调用的方法至多接收两个id参数,要调用其他签名形式的方法可使用
NSInvocation
实现。比如,为调用类似- (void)drawPoint:(CGPoint)point;
形式的方法,可写工具类:参见:NSInvocation更详细用法1
2
3
4
5
6
7
8+ (void)performSelector:(SEL)selector atTarget:(id)target withArgument:(void *)argument {
NSMethodSignature *signature = [target methodSignatureForSelector:selector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
invocation.target = target;
invocation.selector = selector;
[invocation setArgument:argument atIndex:2];
[invocation invoke];
}当object收到未知消息时会调用
- (void)forwardInvocation:(NSInvocation *)anInvocation
,因此有机会转发消息。
预处理指令
为确保文件被引用时开启ARC,添加
1
2
3用
#pragma
supress warning:1
2
3
4
// ...category中方法重载的warning:-Wobjc-protocol-method-implementation
调用deprecated方法的warning:-Wdeprecated-declarations
pragma的其他用法见Pragmas Aren’t Just For Marks
其他
在category中使用Method Swizzle,要在+load()中swizzle,在+initialize()中调用会因category的initialize()和原类中被重载的initialize()的两次调用互相抵消。
NSMutableArray的底层实现
__NSArrayM
是个循环数组,所以在首尾两端插入删除无需移动元素,最坏情况在中间插入删除要移动n/2个元素。插入元素时若空间不足,则空间按1.625倍增长,空间增长后即使删除元素空间也不再变小。见Exposing NSMutableArray给类添加类似array的index存取功能,实现
1
2- (id)objectAtIndexedSubscript:(NSUInteger)idx;
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx;添加类似dict的key存取功能,实现
1
2- (id)objectAtKeyedSubscript:(id <NSCopying>)key;
- (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying>)key;release build中去掉NSLog,在
Prefix.pch
中添加:1
2
3
non-retaining array/set for delegates:
1
2
3
4CFArrayCallBacks callbacks = { 0, NULL, NULL, CFCopyDescription, CFEqual };
NSMutableArray *noRetainArray = (NSMutableArray *)CFArrayCreateMutable(NULL, 0, &callbacks);
NSMutableSet *noRetainSet = (NSMutableSet *)CFSetCreateMutable(NULL, 0, NULL);倒序数组:
1
array.reverseObjectEnumerator.allObjects`
快速遍历含不同类型x值的集合:
1
2id<NSFastEnumeration> collection = values;
for (id object in collection) { … }作为dict键值的object要遵循
<NSCopying>
,如果不遵循又要做键值,使用1
[NSValue valueWithNonretainedObject:object]]
使用block遍历collection:
1
2
3
4
5
6
7
8
9
10
11
12// Array
NSArray *array = /* ... */;
[array enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
}];
// Dictioinary
NSDictionary *dict = /* ... */;
[dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) {
}];
// Set
NSSet *set = /* ... */;
[set enumerateObjectsUsingBlock:^(id object, BOOL *stop) {
}];此外还有带options的版本,如:
enumerateObjectsWithOptions:usingBlock:
。通过options可指定是否并行迭代
NSEnumerationConcurrent
,是否反向迭代NSEnumerationReverse
。使用NSURL.h、NSPathUtilities.h、
NSURLComponents
操作url使用
NSByteCountFormatter
美化下载字节计数:[formatter stringFromByteCount:byteCount]
只在某.m中使用的常量:
全局常量:1
2// .m
static const NSString *kStringConstant = @"VALUE";`1
2
3
4// .h
extern NSString *const EOCStringConstant;
// .m
NSString *const EOCStringConstant = @"VALUE";使用宏
NS_ENUM
和NS_OPTIONS
来定义指定类型的枚举使用NSCache而不是NSDictionary来cache,可在系统内存不足时自动清理
switch语句处理枚举值时不要实现default语句,这样当添加新的枚举值后,编译器会警告你没有处理完所有枚举值