设计模式,,,一个程序猿应一生追求完美的东西
Posted kaihaOS
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式,,,一个程序猿应一生追求完美的东西相关的知识,希望对你有一定的参考价值。
描述一下KVO和KVC。 Key-Value Observing (简写为KVO):当指定的对象的属性被修改了,允许对象接受到通知的机制。每次指定的被观察对象的属性被修改的时候,KVO都会自动的去通知相应的观察者。 KVC是KeyValue Coding的简称,它是一种可以直接通过字符串的名字(key)来访问类属性的机制。而不是通过调用Setter、Getter方法访问。 3简述NotificationCenter、KVC、KVO、Delegate?并说明它们之间的区别? 答:消息中心,消息通知; 利用键-值间接访问类中的某个属性 利用键-路径间接访问类中的某个属性,也称观察者模式 代理,多用于两个类之间的传值 15.你熟悉的设计模式有哪些,请说说对他们的理解。 答:单例,通知,KVO,代理,target-action等 单例,主要特点是一个类只有一个对象。对外提供了一个获取唯一对象的方法,一般都是类方法,完整的单例会重写很多引用计数相关的方法(比如:allocWithZone,copyWithZone,retain,release,autorelease,retainCount等)以保证对象在任何情况下都唯一。单例最大的价值就是建立程序级别的全局变量,就是把不同模块都要用的变量以属性的形式放到单例里面,以便随时使用。音频播放类程序一般会写单例来管理需要播放的音乐信息,需要下载的地方也会以单例的形式来管理下载对象。 通知,是M与C通信的方式之一。一般是Model发送变化的时候,会发送通知告诉Controller,Controller再做相应的处理。需要先往通知中心里面注册观察者,然后在合适的时机,通知中心post通知,观察者做对应的处理,当观察者将要释放的时候,从通知中心移除观察者。 KVO,也是M与C通讯的方式。一般是C去观察M的某个属性,某个属性发生变化之后,C做出相应的处理,当C将要释放的时候,M移除观察者。 代理,是V与C通信的方式之一。一般C是V的代理,V发生变化的时候,C做对应的调整。例如:UITableView被点击了,由Controller做处理。我们在自己写代理的时候,一定要清楚谁来处理事件,谁来调用代理方法。通常情况下都是C处理时间,V在适当的时候调用代理方法。 target-action,也是V与C通信的方式之一。一般C是V的target,V被点击或者被滑动之后,C做出对应的处理。无论是target-action还是代理,核心都是回调。 8.在使用系统的一些类例如UITableView时,会发现其delegate属性的语义设置为assign而不是retain,为什么呢? 答:delegate 的语义修饰符 为assign 不是 retain 主要是为了避免两个对象因相互引用造成的内存泄露问题。 因为 retain修饰delegate,当通过set方法赋值时,对象的引用计数会+1. 如果此时两个对象具有如下关系:A对象有一个属性是B,B的delegate是A。即互相为彼此的属性。例如: A 是viewController ,B是tableView. B 是A的属性,B的引用计数会+1,B的delegate是A,A 的引用计数也会 +1. 那么如果A没有释放,B就一直不会释放,因为A对B有拥有权。 同理,B没有释放,A也一直释放不掉,因为B对A也有拥有权。 因此A 和 B 的dealloc 都会不执行,造成内存泄露. 代码演示如下(只写出了核心代码): A *a = [[A alloc] init] // a 引用计数:1 B *b = [[B alloc] init] // b 引用计数:1 a.b = b; // b 引用计数: 2 b.delegate = a; // a 引用计数: 2 [a release]; // a引用计数: 1 [b release]; // b引用计数: 1 // 最终 A 和 B 都释放不掉。 assign则是直接赋值,并不会引起引用计数增加,因此使用assign 不会出现内存泄露。 代码演示如下(只写出了核心代码): A *a = [[A alloc] init] // a 引用计数:1 B *b = [[B alloc] init] // b 引用计数:1 a.b = b; // b 引用计数: 2 b.delegate = a; // a 引用计数: 1 [a release]; // a引用计数: 0, b引用计数:1(在a的dealloc里面_b被释放了) [b release]; // b引用计数: 0 // 最终 A 和 B 都可以释放掉。 13.NSNotification和KVO的区别和用法是什么?什么时候应该使用通知,什么时候应该使用KVO,它们的实现上有什么区别? 答:通知和KVO都是观察者模式的体现,二者侧重点有些不同。 通知往往用于1对多的场景,多个观察者观察一个通知,一旦这个通知被通知中心post,所有观察者都可以做出响应。具体的实现流程是:(1)通知中心通过addObserver方法添加观察者,其实是把观察者和通知进行绑定,多次使用addObserver方法可以为同一个通知添加多个观察者。(2)通知中心发送通知。(3)各个观察者做各自的处理。(4)在观察者销毁之前(dealloc中),从通知中心移除观察者。 KVO多用于1对1的场景,一个对象去观察另外一个对象的属性值有没有发生变化,一旦发生变化,观察者做出响应。具体的流程是:(1)被观察者添加观察者,指定观察者观察的属性。(2)被观察者的属性在某一时间发生了变化。(3)观察者做出响应。(4)在观察者销毁之前,先移除观察者。 KVO其实也可以1对多,就是多个观察者观察同一个对象同一个属性的变化。KVO和通知给人的感觉一个主动通知(通知会由通知中心主动post),一个是被动通知(KVO,观察者一直盯着属性变没变,一旦变化,自己就做出响应。被观察的对象不是主动告知你我变了)。 23.定义一个返回值为字符串类型,参数是int类型的Block。并且调用该Block。 答:Block定义如下所示: NSString * (^block)(int a) = ^ NSString * (int a) return [NSString stringWithFormat:“%d”,a]; ; Block调用: NSString *str = block(10); 24. 请谈谈你对block和delegate模式认识? 答:无论是block还是delegate模式本质上都是回调,使用block,其优点是回调的block代码块直接就放在了block赋值的地方,使代码更为紧凑,缺点是block内使用到当前类的实例变量的时候,需要注意循环引用的问题,即需要使用__block(MRC下)或者__weak(ARC下)定义一个弱引用的self出来,block里面使用弱引用的self去操作属性或调用方法。delegate模式不用像block一样做特殊处理,但是如果多个对象设置的代理是同一个对象,就需要在delegate方法中判断当前执行代理的是哪个对象。 1、block的作用? 1. __block对象在block中是可以被修改、重新赋值的; 2. __block对象在block中不会被block强引用一次,从而不会出现循环引用的问题。 2、block里面能不能修改静态变量(能,__block可以)为什么要用__block 你可以指定引入一个变量为可更改的,即读-写的,通过应用__block 存储类型修 饰符。局部变量的__block 的存储和 register、auto、static 等存储类型相似,但它们之 间不兼容。 __block 变量保存在变量共享的作用域范围内,所有的 blocks 和 block 副本都声明 或创建在和变量的作用域相同范围内。所以,如果任何 blocks 副本声明在栈内并未超 出栈的结束时,该存储会让栈帧免于被破坏(比如封装为以后执行)。同一作用域范 围内给定的多个 block 可以同时使用一个共享变量 作为一种优化,block存储在栈上面,就像blocks本身一样。如果使用Block_copy 拷贝了 block 的一个副本(或者在 Objective-C 里面给 block 发送了一条 copy 消息), 变量会被拷贝到堆上面。所以一个__block 变量的地址可以随时间推移而被更改。 使用__block 的变量有两个限制:它们不能是可变长的数组,并且它们不能是包 含有 C99 可变长度的数组变量的数据结构。 3、声明一个block 声明block int (^myblock) (int) 说明:第一个 int 是 block 的返回值 myblock 是 block 变量 第二个 int 是参数 // 举例 在.h中 typedef void(^MyBlock)(int value); @property (nonatomic,weak) MyBlock block; -(void)setMyBlock:(void(^)(int value)) block; 在.m中 -(void)setMyBlock:(void(^)(int value)) block if (block) self.block=block; 11、ios使用block应当注意什么? (1)block 在实现时就会对它引用到的它所在方法中定义的栈变量进行一次只读拷贝,然后在 block 块内使用该只读拷贝。 (2)非内联(inline) block 不能直接访问 self,只能通过将 self 当作参数传递到 block 中才能使用,并且此时的 self 只能通过 setter 或 getter 方法访问其属性,不能使用句点式方法。但内联 block 不受此限制。 (3)使用 weak–strong dance 技术来避免循环引用 (4)block 内存管理分析 block 其实也是一个 NSObject 对象,并且在大多数情况下,block 是分配在栈上面的,只有当 block 被定义为全局变量或 block 块中没有引用任何 automatic 变量时,block 才分配在全局数据段上。 __block 变量也是分配在栈上面的。在 ARC 下,编译器会自动检测为我们处理了 block 的大部分内存管理,但当将 block 当作方法参数时候,编译器不会自动检测,需要我们手动拷贝该 block 对象。 在 ARC 下,对 block 变量进行 copy 始终是安全的,无论它是在栈上,还是全局数据段,还是已经拷贝到堆上。对栈上的 block 进行 copy 是将它拷贝到堆上;对全局数据段中的 block 进行 copy 不会有任何作用;对堆上的 block 进行 copy 只是增加它的引用记数。 如果栈上的 block 中引用了__block 类型的变量,在将该 block 拷贝到堆上时也会将 __block 变量拷贝到堆上如果该 __block 变量在堆上还没有对应的拷贝的话,否则就增加堆上对应的拷贝的引用记数。 2.kvo除了能观察属性外,能不能观察对象 不能观察对象 KVO,即:Key-Value Observing,它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知。简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了 KVO是一个对象能够观察另外一个对象的属性的值,并且能够发现值的变化。这是一个对象与另外一个对象保持同步的一种方法,即当另外一种对象的状态发生改变时,观察对象马上作出反应。它只能用来对属性作出反应,而不会用来对方法或者动作作出反应。 实现原理:当为某一个对象属性注册监听的时候,该对象的isa指针就会指向一个中间类,而不是本来对象真实的类。所以说,对象的isa指针可以改变,我们的程序最好不要依赖isa指针。 简而言之就是: 1、当一个object有观察者时,动态创建这个object的类的子类 2、对于每个被观察的property,重写其set方法 3、在重写的set方法中调用- willChangeValueForKey:和- didChangeValueForKey:通知观察者 4、当一个property没有观察者时,删除重写的方法 5、当没有observer观察任何一个property时,删除动态创建的子类 10、简述在app中所应用到设计模式 (一)代理模式 应用场景:当一个类的某些功能需要由别的类来实现,但是又不确定具体会是哪个类实现。 优势:解耦合 敏捷原则:开放-封闭原则 实例:tableview的 数据源delegate,通过和protocol的配合,完成委托诉求。 列表row个数delegate 自定义的delegate (二)观察者模式 应用场景:一般为model层对,controller和view进行的通知方式,不关心谁去接收,只负责发布信息。 优势:解耦合 敏捷原则:接口隔离原则,开放-封闭原则 实例:Notification通知中心,注册通知中心,任何位置可以发送消息,注册观察者的对象可以接收。 kvo,键值对改变通知的观察者,平时基本没用过。 (三)MVC模式 应用场景:是一中非常古老的设计模式,通过数据模型,控制器逻辑,视图展示将应用程序进行逻辑划分。 优势:使系统,层次清晰,职责分明,易于维护 敏捷原则:对扩展开放-对修改封闭 实例:model-即数据模型,view-视图展示,controller进行UI展现和数据交互的逻辑控制。 (四)单例模式 应用场景:确保程序运行期某个类,只有一份实例,用于进行资源共享控制。 优势:使用简单,延时求值,易于跨模块 敏捷原则:单一职责原则 实例:[UIApplication sharedApplication]。 注意事项:确保使用者只能通过 getInstance方法才能获得,单例类的唯一实例。 java,C++中使其没有公有构造函数,私有化并覆盖其构造函数。 object c中,重写allocWithZone方法,保证即使用户用alloc方法直接创建单例类的实例, 返回的也只是此单例类的唯一静态变量。 (五)策略模式 应用场景:定义算法族,封装起来,使他们之间可以相互替换。 优势:使算法的变化独立于使用算法的用户 敏捷原则:接口隔离原则;多用组合,少用继承;针对接口编程,而非实现。 实例:排序算法,NSArray的sortedArrayUsingSelector;经典的鸭子会叫,会飞案例。 注意事项:1,剥离类中易于变化的行为,通过组合的方式嵌入抽象基类 2,变化的行为抽象基类为,所有可变变化的父类 3,用户类的最终实例,通过注入行为实例的方式,设定易变行为 防止了继承行为方式,导致无关行为污染子类。完成了策略封装和可替换性。 (六)工厂模式 应用场景:工厂方式创建类的实例,多与proxy模式配合,创建可替换代理类。 优势:易于替换,面向抽象编程,application只与抽象工厂和易变类的共性抽象类发生调用关系。 敏捷原则:DIP依赖倒置原则 实例:项目部署环境中依赖多个不同类型的数据库时,需要使用工厂配合proxy完成易用性替换 注意事项:项目初期,软件结构和需求都没有稳定下来时,不建议使用此模式,因为其劣势也很明显, 增 加了代码的复杂度,增加了调用层次,增加了内存负担。所以要注意防止模式的滥用。 8.使用block和使用delegate完成委托模式有什么优点? 委托模式在iOS中大量应用,其在设计模式中是适配器模式中的对象适配器,Objective-C中使用id类型指向一切对象,使委托模式更为简洁。 block 优点: 1.语法简洁,实现回调不需要显示的调用方法,代码更为紧凑。 2.增强代码的可读性和可维护性。 3.配合GCD优秀的解决多线程问题。 缺点: 1.Block中得代码将自动进行一次retain操作,容易造成内存泄露。 2.Block内默认引用为强引用,容易造成循环引用。 代理: 优点: 1.减少代码的耦合性,使事件监听和事件处理相分离。 2.清晰的语法定义,减少维护成本,较强的代码可读性。 3.不需要创建第三方来监听事件和传输数据。 4.一个控制器可以实现多个代理,满足自定义开发需求,可选必选有较大的灵活性。 缺点: 1.实现委托的代码过程比较繁琐。 2.当实现跨层传值监听的时候将加大代码的耦合性,并且程序的层次结构将变的混乱。 3.当对多个对象同时传值响应的时候,委托的易用性将 10.何时使用代理,何时使用通知; 代理:一般控件用的比较多,其实也可以用block实现,如果实现的接口比较多的话,建议用代理,如UITableview。 如果一个类能够获取到通知的对象,这种情况下,我们用代理的效率会更高,而且能够更好的实现对要代理的对象的管理。 通知:这东西是全局的,而且是同步的,如果你要全局发送消息,并且做的事情时间不长,不会阻塞线程的话,建议使用。 如果一个通知的发送者有多个接受者,而且接受的位置完全不确定,那么这种情况下用通知是比较好的方式 37. block在ARC中和MRC中的用法有什么区别,需要注意什么 ①.对于没有引用外部变量的Block,无论在ARC还是非ARC下,类型都是__NSGlobalBlock__,这种类型的block可以理解成一种全局的block,不需要考虑作用域问题。同时,对他进行Copy或者Retain操作也是无效的 ②.应注意避免循环引用 36. 类工厂方法是什么 类工厂方法的实现是为了向客户提供方便,它们将分配和初始化合在一个步骤中, 返回被创建的对象,并 进行自动释放处理。这些方法的形式是+ (type)className...(其中 className不包括任何前缀)。 工厂方法可能不仅仅为了方便使用。它们不但可以将分配和初始化合在一起,还可以 为初始化过程提供对 象的分配信息。 类工厂方法的另一个目的是使类(比如NSWorkspace)提供单件实例。虽 然init...方法可以确认一 个类在每次程序运行过程只存在一个实例,但它需要首先分配一个“生的”实例,然后还必须释放该实例。 工厂 方法则可以避免为可能没有用的对象盲目分配内存。 43.代理和协议什么区别 代理是一种概念,协议是一种技术,代理是用协议来实现的,代理 是 2 个对象之间通讯的一种方式。 代理主要做反向传值的。实现系统的一些回调方法,比如 scrollview 滑动事件,选择照片,asi 网络下载完成等.iOS开发和Objective-c区别 50.在block内如何修改block外部变量? 默认情况下,在block中访问的外部变量是复制过去的,即:写操作不对原变量生效。但是你可以加上__block来让其写操作生效,示例代码如下: __block int a = 0; void (^foo)(void) = ^ a = 1; f00(); //这里,a的值被修改为1 53. 使用block时什么情况会发生引用循环,如何解决? 一个对象中强引用了block,在block中又使用了该对象,就会发射循环引用。 解决方法是将该对象使用__weak或者__block修饰符修饰之后再在block中使用。 id weak weakSelf = self; 或者 weak __typeof(&*self)weakSelf = self该方法可以设置宏 id __block weakSelf = self; block中的weak self,是任何时候都需要加的么? (2)block block在copy时都会对block内部用到的对象进行强引用(ARC)或者retainCount增1(非ARC)。在ARC与非ARC环境下对block使用不当都会引起循环引用问题,一般表现为,某个类将block作为自己的属性变量,然后该类在block的方法体里面又使用了该类本身,简单说就是self.someBlock = ^(Type var)[self dosomething];或者self.otherVar = XXX;或者_otherVar = ...;block的这种循环引用会被编译器捕捉到并及时提醒 95.哪些类不适合使用单例模式?即使他们在周期中只会出现一次。 工具类,不需要存储数据的. 简明概要的说明了KVO和NSNotification的区别: 和delegate一样,KVO和NSNotification的作用也是类与类之间的通信,与delegate不同的是1)这两个都是负责发出通知,剩下的事情就不管了,所以没有返回值;2)delegate只是一对一,而这两个可以一对多。这两者也有各自的特点。 1)KVO的使用: 被观察者发出 addObserver:forKeyPath:options:context: 方法来添加观察者。 然后只要被观察者的keyPath值变化(注意:单纯改变其值不会调用此方法,只有通过getters和setters来改变值才会触发KVO),就会在观察者里调用方法observeValueForKeyPath:ofObject:change:context: 因此观察者需要实现方法 observeValueForKeyPath:ofObject:change:context: 来对KVO发出的通知做出响应。 这 些代码都只需在观察者里进行实现,被观察者不用添加任何代码,所以谁要监听谁注册,然后对响应进行处理即可,使得观察者与被观察者完全解耦,运用很灵活很 简便;但是KVO只能检测类中的属性,并且属性名都是通过NSString来查找,编译器不会帮你检错和补全,纯手敲所以比较容易出错。 2)NSNotification的使用 这里的通知不是由被观察者发出,而是由NSNotificationCenter来统一发出,而不同通知通过唯一的通知标识名notificationName来区分,标识名由发送通知的类来起。 首先被观察者自己在必要的方法A里,通过方法postNotificationName:object:来发出通知notificationName这样发送通知者这边的工作就完成了,每次A被调用,就会发送一次通知notificationName。 然后谁要监听A的变化,就通过[NSNotificationCenter defaultCenter]的方法addObserver:selector:name:object:为观察者注册监听name为notificationName的通知然后每次发出name为notificationName的通知时,注册监听后的观察者就会调用其自己定义的方法notificationSelector来进行响应。 NSNotification的特点呢,就是需要被观察者先主动发出通知,然后观察者注册监听后再来进行响应,比KVO多了发送通知的一步,但是其优点是监听不局限于属性的变化,还可以对多种多样的状态变化进行监听,监听范围广,使用也更灵活。 MVC模式及好处? MVC是三个单词的缩写,分别为: 模型(Model),视图(View)和控制Controller)。 MVC模式的目的就是实现Web系统的职能分工。 Model层实现系统中的业务逻辑,通常可以用JavaBean或EJB来实现。 View层用于与用户的交互,通常用JSP来实现。 Controller层是Model与View之间沟通的桥梁,它可以分派用户的请求并选择恰当的视图以用于显示,同时它也可以解释用户的输入并将它们映射为模型层可执行的操作。 MVC模式的好处 1.各施其职,互不干涉 在MVC模式中,三个层各施其职,所以如果一旦哪一层的需求发生了变化,就只需要更改相应的层中的代码而不会影响到其它层中的代码。 2.有利于开发中的分工 在MVC模式中,由于按层把系统开,那么就能更好的实现开发中的分工。网页设计人员可以进行开发视图层中的JSP,对业务熟悉的开发人员可开发业务层,而其它开发人员可开发控层。 3.有利于组件的重用 分层后更有利于组件的重用。如控制层可独立成一个能用的组件,视图层也可做成通用的操作界面。 MVC(Model-View-Controller)应用程序结构被用来分析分布式应用程序的特征。这种抽象结构能有助于将应用程序分割成若干逻辑部件,使程序设计变得更加容易。 MVC结构提供了一种按功能对各种对象进行分割的方法(这些对象是用来维护和表现数的),其目的是为了将各对象间的耦合程度减至最小。MVC结构本来是为了将传统的输入(input)、处理(processing)、输出(output)任务运用到图形化用户交互模型中而设计的。但是,将这些概念运用于基于Web的企业级多层应用领域也是很适合的。 在MVC结构中,模型(Model)代表应用程序的数据(data)和用于控制访问和修改这些数据的业务规则(business rule)。通常模型被用来作为对现实世界中一个处理过程的软件近似,当定义一个模型时,可以采用一般的简单的建模技术。 当模型发生改变时,它会通知视(View),并且为视提供查询模型相关状态的能力。同时,它也为控制器(Controller)提供访问封装在模型内部的应用程序功能的能力。 一个视(View)用来组织模型的内容。它从模型那里获得数据并指定这些数据如何表现。当模型变化时,视负责维持数据表现的一致性。视同时将用户要求告知控制器(Controller)。 控制器(Controller)定义了应用程序的行为;它负责对来自视的用户要求进行解释,并把这些要求映射成相应的行为,这些行为由模型负责实现。在独立运行的GUI客户端,用户要求可能是一些鼠标单击或是菜单选择操作。在一个Web应用程序中,它们的表现形式可能是一些来自客户端的GET或POST的 HTTP请求。模型所实现的行为包括处理业务和修改模型的状态。根据用户要求和模型行为的结果,控制器选择一个视作为对用户请求的应答。通常一组相关功能集对应一个控制器。 1) 各施其职,互不干涉 在MVC模式中,三个层各施其职,所以如果一旦哪一层的需求发生了变化,就只需要更改相应的层中的代码而不会影响到其它层中的代码。假如业务发生了变化,如在取文章时可能webmaster把一些文章作了无效标志,不能直接把所有文章取出来,只能取出有效的文章,这时业务就发生了改变。再设想一下,如果这个业务逻辑在100个页面中都要用到,那么MVC模式就体现了它的灵活性。我们可以不更改任何JSP,只要更改model层中的相应类中的SQL语句即可。 2) 有利于开发中的分工 在MVC模式中,由于按层把系统开,那么就能更好的实现开发中的分工。网页设计人员可以进行开发视图层中的JSP,对业务熟悉的开发人员可开发业务层,而其它开发人员可开发控制层。 3) 有利于组件的重用 分层后更有利于组件的重用。如控制层可独立成一个能用的组件,视力层也可做成通用的操作界面 10、声明block属性的时候为什么⽤用copy? 避免block被系统释放,因为⼀一开始block是在栈中的,只有copy后的block才会 在堆中。 Block属性的声明,⾸首先需要⽤用copy修饰符,因为只有copy后的Block才会在堆 中,栈中的Block的⽣生命周期是和栈绑定的,避免编译器将其释放; (拓展)block与线程安全 另⼀一个需要注意的问题是关于线程安全,在声明Block属性时需要确认“在调⽤用 Block时另⼀一个线程有没有可能去修改Block?”这个问题,如果确定不会有这种 情况发⽣生的话,那么Block属性声明可以⽤用nonatomic。如果不肯定的话(通常 情况是这样的),那么你⾸首先需要声明Block属性为atomic,也就是先保证变量 的原⼦子性(Objective-C并没有强制规定指针读写的原⼦子性,C#有)。 ⽐比如这样⼀一个Block类型: typedef void (^MyBlockType)(int); 属性声明: @property (copy) MyBlockType myBlock; 这⾥里ARC和⾮非ARC声明都是⼀一样的,当然注意在⾮非ARC下要release Block。 但是,有了atomic来保证基本的原⼦子性还是没有达到线程安全的,接着在调⽤用 时需要把Block先赋值给本地变量,以防⽌止Block突然改变。因为如果不这样的 话,即便是先判断了Block属性不为空,在调⽤用之前,⼀一旦另⼀一个线程把Block 属性设空了,程序就会crash,如下代码: if (self.myBlock) //此时,⾛走到这⾥里,self.myBlock可能被另⼀一个线程改为空,造成crash //注意:atomic只会确保myBlock的原⼦子性,这种操作本⾝身还是⾮非线程安全的 self.myBlock(123); 所以正确的代码是(ARC): MyBlockType block = self.myBlock; //block现在是本地不可变的 if (block) block(123); 在⾮非ARC下则需要⼿手动retain⼀一下,否则如果属性被置空,本地变量就成了野指 针了,如下代码: //⾮非ARC MyBlockType block = [self.myBlock retain]; if (block) block(123); [block release]; 4.(口述)NSNotification和KVO的区别和用法是什么?什么时候应该使用通知,什么时候应该使用KVO,它们的实现上有什么区别吗?如果用protocol和delegate(或者delegate的Array)来实现类似的功能可能吗?如果可能,会有什么潜在的问题?如果不能,为什么? 2、非自动内存管理情况下怎么做单例模式 非ARC内存管理模式下对象必须手动释放,为了防止那个唯一的单例对象被释放掉,则只需要重写下面的几个方法即可 + (instancetype) allocWithZone:(struct _NSZone *)zone - (instancetype) copyWithZone:(NSZone*)zone - (id) retain - (oneway void) release - (instancetype) autorelease - (unsigned) retainCount4、What is Singleton pattern? Please try to implement one 单例模式的意思就是只有一个实例。单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。 在iOS中,单例有两种实现方式。根据线程安全的实现来区分,一种是使用@synchronized,另一种是使用GCD的dispatch_once函数。 要实现单例,首先需要一个static的指向类本身的对象,其次需要一个初始化类函数。下面是两种实现的代码。 1、@synchronized static InstanceClass *instance; + (InstanceClass *)defaultInstance @synchronized (self) if (instance == nil) instance = [[InstanceClass alloc] init]; return instance; 2、GCD static InstanceClass *instance; + (InstanceClass *)defaultInstance static dispatch_once_t onceToken; dispatch_once(&onceToken, ^ instance = [[InstanceClass alloc] init]; ); return instance; 2.MRC下的单例需要注意什么 因为 单例对象 是用 static 标记过的 , 因此存放在 静态区 . 所以在 MRC 中 不需要 由程序员 去管理 , 因此要去覆盖一些 内存 管理的方法 . 实现部分与 ARC 一致 , 只需要 覆盖 一些 MRC 中 内存 管理 的方法: * - (id)retain . 单例中不需要增加引用计数器. return self. * - (id)autorelease . 只有堆中的对象才需要 . 单例中不需要.return self. * - (NSUInteger)retainCount . ( 可写可不写 , 防止引起误解 ). 单例中不需要修改引用计数,返回最大的无符号整数即可 .return UINT_MAX; * - (oneway void)release . 不需要 release. 直接覆盖 , 声明也不做 . 单例模式(ARC)与(MRC)
以上是关于设计模式,,,一个程序猿应一生追求完美的东西的主要内容,如果未能解决你的问题,请参考以下文章