OC 中的协议的一些注意点

时间:2021-7-9 作者:qvyue

1. 把相同的属性和方法抽取出来,有哪两种做法?

  • ① 构建父类
  • ② 构建协议

2. 上述的两种做法,有什么不同?

  • ① 类的属性和方法都是和这个类关联的
  • ② 协议的属性和方法不和任何类进行关联,是独立的

3. OC 中调用遵守协议中的方法时,为了确保安全,要怎么做?

  • 要使用 respondsToSelector 进行协议检查,确保确实真的实现了该协议方法

4. 有空练习一下(就能比较彻底明白,UITableViewDelegate 和 UITableViewDataSource)

  • MyView.h 代码如下
// 协议可以用来 view 显示的数据源,也可以用来 view 的代理使用,典型的例子就是 UITableView;
// 有 返回值 的作为数据源使用,没有返回值的作为 代理 使用

#import 

@protocol MyViewDataSource 

- (NSUInteger)numbersOfPeople;
- (NSString *)titleForView;

@end

@protocol MyViewDelegate 

- (void)myViewPayButtonDidClick;

@end

@interface MyView : UIView

@property (nonatomic, weak, nullable) id dataSource;
@property (nonatomic, weak, nullable) id delegate;

- (void)reload;

@end
  • MyView.m 代码如下

#import "MyView.h"

@interface MyView ()

@property(nonatomic, strong) UILabel *titleLabel;
@property(nonatomic, strong) UILabel *peopleLabel;

@property(nonatomic, strong) UIButton *payButton;
@end

@implementation MyView

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 100, 300, 44)];
        self.titleLabel.text = @"默认标题";
        [self addSubview:self.titleLabel];
        
        self.peopleLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 200, 300, 44)];
        self.peopleLabel.text = @"默认人数 0";
        [self addSubview:self.peopleLabel];
        
        self.payButton = [UIButton buttonWithType:UIButtonTypeSystem];
        self.payButton.frame = CGRectMake(20, 300, 300, 44);
        [self.payButton setTitle:@"付款按钮" forState:UIControlStateNormal];
        [self addSubview:self.payButton];
        [self.payButton addTarget:self action:@selector(payButtonAction) forControlEvents:UIControlEventTouchUpInside];
        
    }
    return self;
}

- (void)reload {
    if (self.dataSource && [self.dataSource respondsToSelector:@selector(titleForView)]) {
        self.titleLabel.text = [self.dataSource titleForView];
    }
    
    if (self.dataSource && [self.dataSource respondsToSelector:@selector(numbersOfPeople)]) {
        self.peopleLabel.text = [NSString stringWithFormat:@"具体人数 %lu", (unsigned long)[self.dataSource numbersOfPeople]];
    }
}

- (void)payButtonAction {
    if ([self.delegate respondsToSelector:@selector(myViewPayButtonDidClick)]) {
        [self.delegate myViewPayButtonDidClick];
    }
}

@end
  • ProtocolViewController.m 调用代码如下

#import "ProtocolViewController.h"
#import "MyView.h"

@interface ProtocolViewController ()

@property(nonatomic, strong) MyView* myView;
@property(nonatomic, assign) NSUInteger peopleCount;

@end

@implementation ProtocolViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    self.myView = [[MyView alloc] init];
    [self.view addSubview:self.myView];
    [self.myView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.view);
    }];
    self.myView.dataSource = self;
    self.myView.delegate = self;
}


- (void)myViewPayButtonDidClick {
    NSLog(@"控制器收到点击事件");
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"touchesBegan");
    [self.myView reload];
}

- (NSUInteger)numbersOfPeople {
    return ++self.peopleCount;
}

- (nonnull NSString *)titleForView {
    return @"来自控制器的标题";
}


@end

5. 思考如下问题

  • 如果把上述代码中 MyView.h 的 dataSource 改为如下声明
@property (nonatomic, weak, nullable) id dataSource;
  • 请问在 MyView.m 文件中,下面代码能编译通过吗(不考虑运行时错误)?
- (void)reload {
    [self.delegate myViewPayButtonDidClick];
}
  • 上述代码能编译通过,但是在运行时会报错
  • 按照目前的理解是类型为 id类型 的实例可以调用它能拿到的所有成员方法
  • Class 身上有同样的特质,能调用 Class 在当前上下文中访问到的所有类方法
Class myClass = nil;
[myClass canCallAllClassMethod];
声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:qvyue@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。