Objective-C语言
- 分类(什么是分类?分类的实现机制、原理是怎样的?我们应该怎样为一个分类提供实例变量呢?--涉及到第2点关联对象的考察)
- 关联对象(Runtime分析和查看 分类和关联对象的实现机制、原理)
- 扩展、代理怎么使用(分类和扩展的区别在哪里?)
- NSNotification(通知的实现机制和原理)
- KVO、KVC( KVO、KVC的实现机制、原理、包括涉及到了哪些设计思想)
- 属性关键字(声明属性时,会用到一些关键字的实际问题)
扩展extension(内部的私有声明。一般用扩展来做什么?)
- 声明私有属性,是可以不对子类暴露的
- 声明私有方法,方便阅读
- 声明私有成员变量
扩展的特点:
- 编译时决议
- 只以声明的形式存在,没有具体实现,多数情况寄生于宿主类的.m中,也就是说,它不是独立存在实现的一个文件
可以把扩展理解为类的一个内部的私有声明 - 不能为系统类添加扩展
分类和扩展的区别:
- 分类是运行时决议,扩展是编译时决议
- 分类可以有声明有实现,而扩展只有声明,它的实现是直接写在宿主类当中
- 可以为系统类添加分类,但不能为系统类添加扩展
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):
什么是代理:
- 准确的说是一种软件设计模式,代理模式
- iOS当中以@protocol形式体现
- 传递方式是一对一
代理的工作流程:
- 委托方会要求代理放需要实现的接口,全部定义在协议当中
- 在协议当中可以声明属性,也可以声明方法
- 代理费按照协议实现方法
- 代理费返回一个处理结果给委托方
- 委托方需要调用代理方遵从的协议方法
首先定义一个协议类,来定义公共协议
#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(存放数据模型),里面存放观察者对象。如下图