delegate方法比notification更加直接,最典型的特征是,delegate方法往往需要关注返回值, 也就是delegate方法的结果。比如-windowShouldClose:,需要关心返回的是yes还是no。所以delegate方法往往包含 should这个很传神的词。也就是好比你做我的delegate,我会问你我想关闭窗口你愿意吗?你需要给我一个答案,我根据你的答案来决定如何做下一 步。相反的,notification最大的特色就是不关心接受者的态度, 我只管把通告放出来,你接受不接受就是你的事情,同时我也不关心结果。所以notification往往用did这个词汇,比如 NSWindowDidResizeNotification,那么NSWindow对象放出这个notification后就什么都不管了也不会等待接受者的反应。
和delegate一样,KVO和NSNotification的作用也是类与类之间的通信,与delegate不同的是1)这两个都是负责发出通知,剩下的事情就不管了,所以没有返回值;2)delegate只是一对一,而这两个可以一对多。这两者也有各自的特点。
所谓的“手动触发”是区别于“自动触发”:
自动触发是指类似这种场景:在注册 KVO 之前设置一个初始值,注册之后,设置一个不一样的值,就可以触发了。
想知道如何手动触发,必须知道自动触发 KVO 的原理:
键值观察通知依赖于 NSObject 的两个方法: willChangeValueForKey: 和 didChangevlueForKey: 。在一个被观察属性发生改变之前, willChangeValueForKey: 一定会被调用,这就 会记录旧的值。而当改变发生后, observeValueForKey:ofObject:change:context: 会被调用,继而 didChangeValueForKey: 也会被调用。如果可以手动实现这些调用,就可以实现“手动触发”了。
那么“手动触发”的使用场景是什么?一般我们只在希望能控制“回调的调用时机”时才会这么做。
具体做法如下:
如果这个 value 是 表示时间的 self.now ,那么代码如下:最后两行代码缺一不可。
相关代码已放在仓库里。
NSString、NSArray、NSDictionary 等等经常使用copy关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary;
用 @property 声明 NSString、NSArray、NSDictionary 经常使用 copy 关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary,他们之间可能进行赋值操作,为确保对象中的字符串值不会无意间变动,应该在设置新属性值时拷贝一份。
delegate运行成本低。block成本很高的。而且delegate是经典设计模式也就是大部分的语言都可以实现的模式,相对block出现比较早。block出栈需要将使用的数据从栈内存拷贝到堆内存,当然对象的话就是加计数,使用完或者block置nil后才消除。delegate只是保存了一个对象指针,直接回调,没有额外消耗。相对C的函数指针,只多做了一个查表动作
##
根据苹果文档对Runtime的解释
id objc_msgSend(id self, SEL _cmd, ...)
将一个消息发送给一个对象,并且返回一个值。
self是消息的接受者,
_cmd是selector,
…是可变参数列表。
消息转发和发送
load和initialize方法都会在实例化对象之前调用,以main函数为分水岭,前者在main函数之前调用,后者在之后调用。这两个方法会被自动调用,不能手动调用它们。
load和initialize方法都不用显示的调用父类的方法而是自动调用,即使子类没有initialize方法也会调用父类的方法,而load方法则不会调用父类。
load方法通常用来进行Method Swizzle,initialize方法一般用于初始化全局变量或静态变量。
load和initialize方法内部使用了锁,因此它们是线程安全的。实现时要尽可能保持简单,避免阻塞线程,不要再使用锁。
文/bestswifter(简书作者)
原文链接: http://www.jianshu.com/p/d25f691f0b07
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
我们想跟踪在程序中每一个view controller展示给用户的次数:当然,我们可以在每个view controller的viewDidAppear中添加跟踪代码;但是这太过麻烦,需要在每个view controller中写重复的代码。创建一个子类可能是一种实现方式,但需要同时创建UIViewController, UITableViewController, UINavigationController及其它UIKit中view controller的子类,这同样会产生许多重复的代码。
在Objective-C中,运行时会自动调用每个类的两个方法。+load会在类初始加载时调用,+initialize会在第一次调用类的类方法或实例方法之前被调用。这两个方法是可选的,且只有在实现了它们时才会被调用。由于method swizzling会影响到类的全局状态,因此要尽量避免在并发处理中出现竞争的情况。+load能保证在类的初始化过程中被加载,并保证这种改变应用级别的行为的一致性。相比之下,+initialize在其执行时不提供这种保证—事实上,如果在应用中没为给这个类发送消息,则它可能永远不会被调用。
与上面相同,因为swizzling会改变全局状态,所以我们需要在运行时采取一些预防措施。原子性就是这样一种措施,它确保代码只被执行一次,不管有多少个线程。GCD的dispatch_once可以确保这种行为,我们应该将其作为method swizzling的最佳实践。
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
// When swizzling a class method, use the following:
// Class class = object_getClass((id)self);
SEL originalSelector = @selector(viewWillAppear:);
SEL swizzledSelector = @selector(xxx_viewWillAppear:);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod =
class_addMethod(class,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
});
}
isKindOfClass和isMemberOfClass之间的区别是:
我们可以使用isKindOfClass来确定一个对象是否是一个类的实例,或者是该类祖先类的实例。
isMemberOfClass只能用来判断前者,不能用来判断后者。
可以说:isMemberOfClass不能检测任何的类都是基于NSObject类这一事实,而isKindOfClass可以。
其实,如果不考虑其他任何因素和技术,多线程有百害而无一利,只能浪费时间,降低程序效率。
是的,我很清醒的写下这句话。
试想一下,一个任务由十个子任务组成。现在有两种方式完成这个任务: 1. 建十个线程,把每个子任务放在对应的线程中执行。执行完一个线程中的任务就切换到另一个线程。
操作系统的基础知识告诉我们,线程,是执行程序最基本的单元,它有自己栈和寄存器。说得再具体一些,线程就是“一个CPU执行的一条无分叉的命令列”。
对于第一种方法,在十个线程之间来回切换,就意味着有十组栈和寄存器中的值需要不断地被备份、替换。 而对于对于第二种方法,只有一组寄存器和栈存在,显然效率完胜前者
GCD:
三种队列:
串行队列(先进入队列的任务先出队列,每次只执行一个任务)
并发队列(依然是“先入先出”,不过可以形成多个任务并发)
主队列(这是一个特殊的串行队列,而且队列中的任务一定会在主线程中执行)
两种执行方式:
同步执行
异步执行
iOS多线程编程——GCD与NSOperation总结
typedef struct objc_method *Method;
struct objc_method {
SEL method_name; // 方法名称
charchar *method_typesE; // 参数和返回类型的描述字串
IMP method_imp; // 方法的具体的实现的指针
}
runtime对注册的类,会进行布局,对于weak对象会放入一个hash表中,用weak指向的对象内存地址作为key,当此对象的引用计数为0的时候会dealloc,加入weak指向的对象内存地址是a,那么就以a为键,在这个weak表中搜索,找到所有以a为键的weak对象,从而设置为nil。 (网上看到的。。)
废话不多说,直接上要点列表:
同样,直接整理要点: