美文网首页iOS 开发 Objective-C
OC 中的协议的一些注意点

OC 中的协议的一些注意点

作者: 望穿秋水小作坊 | 来源:发表于2021-06-24 10:42 被阅读0次

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

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

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

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

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

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

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

    • MyView.h 代码如下
    // 协议可以用来 view 显示的数据源,也可以用来 view 的代理使用,典型的例子就是 UITableView;
    // 有 返回值 的作为数据源使用,没有返回值的作为 代理 使用
    
    #import <UIKit/UIKit.h>
    
    @protocol MyViewDataSource <NSObject>
    
    - (NSUInteger)numbersOfPeople;
    - (NSString *)titleForView;
    
    @end
    
    @protocol MyViewDelegate <NSObject>
    
    - (void)myViewPayButtonDidClick;
    
    @end
    
    @interface MyView : UIView
    
    @property (nonatomic, weak, nullable) id<MyViewDataSource> dataSource;
    @property (nonatomic, weak, nullable) id<MyViewDelegate> 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 ()<MyViewDataSource, MyViewDelegate>
    
    @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<UITouch *> *)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];
    

    相关文章

      网友评论

        本文标题:OC 中的协议的一些注意点

        本文链接:https://www.haomeiwen.com/subject/ccewyltx.html