Note
strong©&mutablecopy
- strong修饰的属性无论是可变或不可变都是浅拷贝
- copy修饰的属性,不可以变的浅拷贝,可变的深拷贝
- mutablecopy修饰的属性都是深拷贝
- 容器内元素默认都是指针拷贝, 而不是内容复制
如何使对象具有拷贝功能
- 必须实现NSCopying协议或NSMutableCopying协议
- 实现-(id)copyWithZone:(NSZone *)zone;
UIView&CALayer UIView主要对显示内容的管理, CALayer侧重显示内容的绘制
• 每个 UIView 内部都有一个 CALayer 在背后提供内容的绘制和显示,并且 UIView 的尺寸样式都由内部的 Layer 所提供。两者都有树状层级结构,layer 内部有 SubLayers,View 内部有 SubViews.但是 Layer 比 View 多了个AnchorPoint
• 在 View显示的时候,UIView 做为 Layer 的 CALayerDelegate,View 的显示内容由内部的 CALayer 的 display
• CALayer 是默认修改属性支持隐式动画的,在给 UIView 的 Layer 做动画的时候,View 作为 Layer 的代理,Layer 通过 actionForLayer:forKey:向 View请求相应的 action(动画行为)
• layer 内部维护着三分 layer tree,分别是 presentLayer Tree(动画树),modeLayer Tree(模型树), Render Tree (渲染树),在做 iOS动画的时候,我们修改动画的属性,在动画的其实是 Layer 的 presentLayer的属性值,而最终展示在界面上的其实是提供 View的modelLayer
• 两者最明显的区别是 View可以接受并处理事件,而 Layer 不可以
self和super
NSStringFromClass([self class]) = Son
NSStringFromClass([super class]) = Son
super它的本质是一个编译器标识符,和self是指向同一消息接受体
区别是:
self调用方法时,会从当前类的方法列表中开始找,如果没有就从父类中再找.
super则是从父类的方法列表中开始找,然后调用父类的这个方法
还有就是"不推荐init方法中使用点语法",访问实例变量应使用下划线,因为子类可以重写父类的setter方法
isa
isa: 是一个Class类型的指针,每个实例对象都有个isa指针,指向对象的类,而Class里也有个isa指针,指向metaClass(元类).元类保存了类方法的列表,当类方法调用时, 先从自身查找类方法的实现, 如果没有,元类会向他父类查找该方法,同时注意的是元类(metaClass)也是类,也是对象==类对象,元类也有isa指针,它的isa指针最终指向的是一个根元类(root metaClass),根元类的isa指针指向本身,这样就形成了一个封闭的被循环
什么时候会报unrecognized selector的异常?也就是发消息给未实现的方法,详细都发生了什么事情
当调用该对象上某个方法,而该对象上没有实现这个方法的时候,可以通过"消息转发"进行解决
objc在向一个对象发送未实现的消息时,会通过下面三次机会避免程序崩溃
第一次---利用runtime对方法进行动态实现
如果objc对象发送的消息未实现,那runtime就会调用
+resolveInstanceMethod:
+resolveClassMethod:
然后再其中一个方法中通过class_addMethod动态实现该方法,避免程序崩溃
void dynamicMethodIMP(id self, SEL _cmd){
NSLog(@"我是动态实现的方法");
}
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
if (sel == @selector(myclassName)){
class_addMethod([self class], sel, (IMP)dynamicMethodIMP, "v@");
return YES;
}
return [super resolveInstanceMethod:sel];
}
第二次---消息的快速转发
如果目标对象实现了-forwardingTargetForSelector:,Runtime这时就会调用这个方法,给这个消息调用其他对象的机会
//消息转发给其他类去调用
- (id)forwardingTargetForSelector:(SEL)aSelector
{
if (aSelector == @selector(myclassName)){
return [Other new];
}
return nil;
}
• 这里叫Fast,只是为了区别下一步的转发机制。因为这一步不会创建任何新的对象,但Normal forwarding转发会创建一个NSInvocation对象,相对Normal forwarding转发更快点,所以这里叫Fast forwarding
第三次机会---消息的正常转发
先获取消息选择器,然后发送给实现了这个方法的对象
//先返回消息选择器
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
if ([NSStringFromSelector(aSelector) isEqualToString:@"myclassName"]){
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
return [super methodSignatureForSelector:aSelector];
}
//转发消息到可调用的对象
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
[anInvocation invokeWithTarget:[Xother new]];
}
@property的本质
"属性"(property)有两大概念.生成ivar(实例变量)
生成存取器(access method = getter + setter)
何时使用copy
- NSString, NSArray, NSDictionary经常使用copy关键字, 是因为他们有对应的可变类型, NSMutableString, NSMutableArray, NSMutableDictionary
- block MRC中,方法内部的block是在栈区的, 使用copy可以把它放到堆区, 在ARC中写不写都行, 使用copy和strong效果是一样的
weak和assign
- 使用weak解决循环引用
- 拖控件到xib或storyboard已经对视图强引用,在拖线的时候需要用weak
- assign可以用非OC对象, 而weak必须用于OC对象
- 在强引用被销毁的时候, weak也被置为nil,更安全
KVO内部实现原理---基于runtime机制实现
1, 动态创建该类的派生类
2, 在派生类中重写被观察属性的setter方法
3, 在重写的setter方法内,实现真正的通知机制
健值观察依赖NSObject的
willChangeValueForKey:
didChangevalueForKey:
KVC的使用以及原理
KVC-键值编码
不适用KVC访问属性
- 取值
CYXModel *model = [[CYXModel alloc]init];
NSString *name = model. name;
CYXShopModel *shop = model. product;
NSString *productName = shop. productName
- 设值
CYXModel *model = [[CYXModel alloc]init];
model. name = @"CYX";
CYXShopModel *shopModel = [[CYXShopModel alloc]init];
shopModel. productName = @"NIKE"; model. product = shopModel;
使用KVC访问属性
- 取值
CYXModel *model = [[CYXModel alloc]init];
NSString *name = [model valueForKey: @"name" ];
NSString *productName = [model valueForKeyPath: @"product.productName" ];
- 设值
CYXModel *model = [[CYXModel alloc]init];
[model setValue:@"CYX" forKey:@"name"];
[model setValue:@"NIKE" forKeyPath:@"product.productName"];
使用场景
1, 修改系统空间的内部属性(runtime + KVC)
如实现UIPageController的标识点改成横线的需求
先用runtime遍历UIPageController是属性列表
然后用KVC对属性进行赋值
key和keyPath的区别就是,keyPath解决属性反复嵌套
高性能设置图片圆角
- 绘图技术
- 贝塞尔曲线切割
生命周期
- loadView
- DidLoadView
- viewWillAppear
- viewWillLayoutSubviews
- viewDidLayoutSubviews
- viewDidAppear
- viewWillDisAppear
- viewDodDisAppear
- didReceiveMemoryWarning
- viewWillUnload
- viewDidUnload
对象的内存布局
NSObject -> Father -> Son
有一个对象son
- 所有父类的成员变量和自己的成员变量都存放在该对象对应的存储空间中
- 父类的方法和自己的方法都会缓存在类对象的方法缓存中, 类方法是缓存在元类中(NSObject)
- 每个对象内部都有一个isa指针,指向它的类对象, 类对象中存放着本对象的如下信息
1, 对象方法列表
2, 成员变量列表
3, 属性列表
dispatch_barrier_async
- 必须是并发队列, 要是串行队列就没意义了
- dispatch_barrier_async第一个参数不能是全局并发队列
- 它前面的任务执行完,它才执行, 它执行完, 它后面的任务才执行