iOS 设计模式(I)

1. 设计模式是什么? 你知道哪些设计模式,并简要叙述?

设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类型的事情。
1). MVC模式:Model View Control,把模型 视图 控制器 层进行解耦合编写。
2). MVVM模式:Model View ViewModel 把模型 视图 业务逻辑 层进行解耦和编写。
3). 单例模式:通过static关键词,声明全局变量。在整个进程运行期间只会被赋值一次。
4). 观察者模式:KVO是典型的通知模式,观察某个属性的状态,状态发生变化时通知观察者。
5). 委托模式:代理+协议的组合。实现1对1的反向传值操作。
6). 工厂模式:通过一个类方法,批量的根据已有模板生产对象。


2. 什么是 KVO 和 KVC?


1). KVC(Key-Value-Coding):键值编码 是一种通过字符串间接访问对象的方式(即给属性赋值)
    举例说明:
    stu.name = @"张三" // 点语法给属性赋值
    [stu setValue:@"张三" forKey:@"name"]; // 通过字符串使用KVC方式给属性赋值
    stu1.nameLabel.text = @"张三";
    [stu1 setValue:@"张三" forKey:@"nameLabel.text"]; // 跨层赋值
2). KVO(key-Value-Observing):键值观察机制 他提供了观察某一属性变化的方法,极大的简化了代码。
     KVO只能被KVC触发,包括使用setValue:forKey:方法和点语法。
   // 通过下方方法为属性添加KVO观察
   - (void)addObserver:(NSObject *)observer
                     forKeyPath:(NSString *)keyPath
                     options:(NSKeyValueObservingOptions)options
                     context:(nullable void *)context;
   // 当被观察的属性发送变化时,会自动触发下方方法                   
   - (void)observeValueForKeyPath:(NSString *)keyPath
                              ofObject:(id)object
                                  change:(NSDictionary *)change
                                 context:(void *)context{}
    
KVC 和 KVO 的 keyPath 可以是属性、实例变量、成员变量。



3. KVC的底层实现?

KVO基于runtime机制实现。

当一个对象调用setValue方法时,方法内部会做以下操作:
1). 检查是否存在相应的key的set方法,如果存在,就调用set方法。
2). 如果set方法不存在,就会查找与key相同名称并且带下划线的成员变量,如果有,则直接给成员变量属性赋值。
3). 如果没有找到_key,就会查找相同名称的属性key,如果有就直接赋值。
4). 如果还没有找到,则调用valueForUndefinedKey:和setValue:forUndefinedKey:方法。
这些方法的默认实现都是抛出异常,我们可以根据需要重写它们。



4. 实现一个线程安全的单例模式

static Persons *_person = nil;

+ (id) allocWithZone:(struct _NSZone *)zone {
          static dispatch_onec_t onceToken;
          dispatch_once(&onceToken, ^{
                 _person = [super allocWithZone:zone];
          });
  return _person;
}

- (instance) shareInstance {
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    _person =[ [self alloc] init];
  });
  return _person;
}

- (id) copyWithZone:(NSZone *)zone {
  return _person;
}




5. NSNotification和KVO的区别和用法是什么?什么时候应该使用通知,什么时候应该使用KVO,它们的实现上有什么区别吗?如果用protocol和delegate(或者delegate的Array)来实现类似的功能可能吗?如果可能,会有什么潜在的问题?如果不能,为什么?




6. 怎么实现单例, 2种方法实现(喜马拉雅面试)问题

//第一种方式:线程安全的单例2(不推荐 效率低)
+ (instancetype)shareSingleton2 {
    @synchronized(self) {
        if (!singleton) {
            singleton = [[self alloc]init];
        }
    }
    return singleton;
}

//第二种方式 线程安全的单例
+ (instancetype)shareSingleton {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        singleton = [[self alloc]init];
    });
    return singleton;
}

然而仅仅知道这些是不够的,说了上面的,面试官会继续问单例,怎么实现的,加锁了吗?单例什么时候释放?然后你就会一脸懵~有同感的举个手

  • 单例,怎么实现的,加锁了吗?单例什么时候释放
    其实在上面的两个单例的创建中,@synchronized是一个锁,后面会讲到,就是说第一种是通过加锁的方式来实现,而第二种解析如下:
    GCD创建:dispatch_once中dispatch_once_t类型为typedef long
    • onceToken= 0,线程执行dispatch_once的block中代码
    • onceToken= -1,线程跳过dispatch_once的block中代码不执行
    • onceToken= 其他值,线程被线程被阻塞,等待onceToken值改变
    用途:限制创建,提供全局调用,节约资源和提高性能。参考
    常见的应用场景:
    • UIApplication
    • NSNotificationCenter
    • NSFileManager
    • NSUserDefaults
    • NSURLCache
    • NSHTTPCookieStorage

那么单例是怎么销毁的呢?如下:

方法一:
+(void)attemptDealloc{
    [_instance release]; //mrc 需要释放,当然你就不能重写release的方法了.
    _instance = nil;
}


方法二:
1. 必须把static dispatch_once_t onceToken; 这个拿到函数体外,成为全局的.
2.
+(void)attempDealloc{
    onceToken = 0; // 只有置成0,GCD才会认为它从未执行过.它默认为0.这样才能保证下次再次调用shareInstance的时候,再次创建对象.
    [_instance release];
    _instance = nil;
 }



7. kvo 里面什么时候修改属性的stter方法的?

中间类在被观察的属性的setter方法中,在改变属性值的前后分别添加了willChangeValueForKey:和didChangeValueForKey:。使其在通过KVC标准改变属性值时可以被观察到,并向观察者发送消息。



``




``




``




``




``




``




``




``




``




``




``




``




``




``




``




``




``




``


你可能感兴趣的:(iOS 设计模式(I))