iOS面试题(九)Objective-C语言 -扩展&代理&通知

Objective-C语言

  1.  分类(什么是分类?分类的实现机制、原理是怎样的?我们应该怎样为一个分类提供实例变量呢?--涉及到第2点关联对象的考察)
  2. 关联对象(Runtime分析和查看 分类和关联对象的实现机制、原理)
  3. 扩展、代理怎么使用(分类和扩展的区别在哪里?)
  4. NSNotification(通知的实现机制和原理)
  5. KVO、KVC( KVO、KVC的实现机制、原理、包括涉及到了哪些设计思想)
  6. 属性关键字(声明属性时,会用到一些关键字的实际问题)

扩展extension(内部的私有声明。一般用扩展来做什么?)

  1. 声明私有属性,是可以不对子类暴露的
  2. 声明私有方法,方便阅读
  3. 声明私有成员变量

扩展的特点:

  1. 编译时决议
  2. 只以声明的形式存在,没有具体实现,多数情况寄生于宿主类的.m中,也就是说,它不是独立存在实现的一个文件
    可以把扩展理解为类的一个内部的私有声明
  3. 不能为系统类添加扩展

分类和扩展的区别:

  1. 分类是运行时决议,扩展是编译时决议
  2. 分类可以有声明有实现,而扩展只有声明,它的实现是直接写在宿主类当中
  3. 可以为系统类添加分类,但不能为系统类添加扩展

ps(小记):
创建扩展:
通过New File -> Objective-C extension来创建,比如我选择ASStudent类,延展名叫hello,那么会自动创建一个.h文件叫ASStudent_hello.h, 没有.m文件,因为可以直接在类的.m里写即可。(这个也正是和分类的不同,分类会有.h 和 .m)
使用格式:
@interface Mitchell()
//属性   //方法
@end
摘自网上的一段话:
a:我们可以不通过创建文件来创建延展,可以直接在.m文件里写@interface和@implementation, 注意这两个都要写在.m文件里,因为如果把@interface写在.h里,那么里面的方法都是public的;
b:此外,我们也可以直接省略@interface,直接在.m文件里写方法即可,但还是建议书写@interface,这样的好处是可阅读性强,可以在文件一开始的几行就告知了哪些是私有方法。
这正好解释了,为什么大神会说扩展其实无处不在了。


代理(Delegate):

什么是代理:

  1. 准确的说是一种软件设计模式,代理模式
  2. iOS当中以@protocol形式体现
  3. 传递方式是一对一

代理的工作流程:
 

  1. 委托方会要求代理放需要实现的接口,全部定义在协议当中
  2. 在协议当中可以声明属性,也可以声明方法
  3. 代理费按照协议实现方法
  4. 代理费返回一个处理结果给委托方
  5. 委托方需要调用代理方遵从的协议方法

首先定义一个协议类,来定义公共协议

#import <Foundation/Foundation.h>
@protocol LoginProtocol <NSObject>
@optional
- (void)userLoginWithUsername:(NSString *)username password:(NSString *)password;
@end

定义委托类,这里简单实现了一个用户登录功能,将用户登录后的账号密码传递出去,有代理来处理具体登录细节。

#import <UIKit/UIKit.h>
#import "LoginProtocol.h"
/**
 *  当前类是委托类。用户登录后,让代理对象去实现登录的具体细节,委托类不需要知道其中实现的具体细节。
 */
@interface LoginViewController : UIViewController
// 通过属性来设置代理对象
@property (nonatomic, weak) id<LoginProtocol> delegate;
@end

实现部分:

@implementation LoginViewController
- (void)loginButtonClick:(UIButton *)button {
  // 判断代理对象是否实现这个方法,没有实现会导致崩溃
  if ([self.delegate respondsToSelector:@selector(userLoginWithUsername:password:)]) {
      // 调用代理对象的登录方法,代理对象去实现登录方法
      [self.delegate userLoginWithUsername:self.username.text password:self.password.text];
  }
}

代理方,实现具体的登录流程,委托方不需要知道实现细节。

// 遵守登录协议
@interface ViewController () <LoginProtocol> 
@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];

    LoginViewController *loginVC = [[LoginViewController alloc] init];
    loginVC.delegate = self;
    [self.navigationController pushViewController:loginVC animated:YES];
}

/**
 *  代理方实现具体登录细节
 */
- (void)userLoginWithUsername:(NSString *)username password:(NSString *)password {
    NSLog(@"username : %@, password : %@", username, password);
}

 

这里我们需要知道一下,协议中可以定义哪些内容?协议可以通过@required定义必须实现的代理方法,通过@optional定义可选方法

在我们实际开发中,委托方和代理方的关系应该怎么样建立,他们建立的关系的过程中,应该注意哪些问题?

在使用代理的时候,存在一个循环引用的问题,当代理,协议,委托都通过强引用(strong)形成一个闭环,则会造成内存泄露的问题,此时我们通常会让委托方弱(weak)引用指向代理方来避免循环引用。

通知(NSNotification)

  • 使用观察者模式来实现的、用于跨层传递消息的机制(一般数据处理逻辑是网络层传递到数据层,然后在经过业务逻辑层加工再去更新UI。如果有时候网络层返回的数据不经过业务逻辑层,直接到达UI层,这时候就用到跨层传递)
  • 传递方式为一对多

 

   通知和代理的区别:

  • 通知是观察者模式来实现,代理是由代理模式实现的。
  • 通知传递方式是一对多。代理是传递方式是一对一。

如何实现通知机制?
首先,信息的传递就依靠通知(NSNotification),也就是说,通知就是信息(执行的方法,观察者本身(self),参数)的包装。通知中心(NSNotificationCenter)是个单例,向通知中心注册观察者,也就是说,这个通知中心有个集合,这个集合存放着观察者。
那么这个集合是什么样的数据类型 ? 大概猜想: 发送通知需要name参数,添加观察者也有个name参数,这两个name一样的时候,当发送通知时候,观察者对象就能接受到信息,执行对应的操作。猜想这个集合是NSDictionary。
key就是name,value就是NSArray(存放数据模型),里面存放观察者对象。如下图 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值