黑马程序员——OC语言基本语法知识(五)

时间:2023-02-18 20:52:52

block :用来保存一段代码,用^

 1、block 特点:
  1> Block封装了一段代码,可以在任何时候执行 
  2> Block可以作为函数或者函数的返回值,而其本身又可以带输入参数或返回值
  3> 苹果官方建议尽量多用block,在多线程、异步任务、集合遍历、集合排序、动画转场用的很多
  4> Block可以在程序运行时凭空产生一个代码保存起来
 2、block的标志:^
 3、block跟函数很像
  1> 可以保存代码
  2> 有返回值
  3> 有形参
  4> 调用方式一样
 4、定义block变量(没有形参)
  1> myblock是变量名,后面的()代表没有形参
   void (^myblock)() = ^(){
   NSLog(@"-----------");
   NSLog(@"-----------");
   };
  2> 没有形参可以省略后面的小括号
  void (^myblock)() = ^{
      NSLog(@"-----------");
      NSLog(@"-----------");
  };

  3> 利用block变量调用block内部的代码
  myblock();
 
5、定义指向函数的指针int(*p)(int, int); 能用指向函数的指针做的东西一般用block替代
6、定义block变量(有形参)
  1> 返回值是int,接收两个int类型的参数
  int (^sumblock)(int,int) = ^( int n1, int n2 ){
      return n1+n2;
  };
  2> 调用
  int a =  sumblock(3,4);
  3> 输出
  NSLog(@"%d", a);
7、使用typedef定义指向函数的指针类型
typedef int (*SumP)(int,int);
8、使用typedef定义block类型
  1> typedef int (^MyBlock)(int,int);
  2> 用block计算两个值的和
  MyBlock sumBlock = ^(int  a, int b){
      return a + b;
   };

小结
block要掌握的东西
 1、如何定义block变量
 int (^sumBlock)(int,int);
 void(^myBlock);
 
 2、如何利用block封装代码
  1> 有形参
 ^(int a, int b) {
    return a-b;
 }
  2> 没有形参
 ^() {
    NSLog(@"----");
 }
 
 ^() {
 NSLog(@"----");
 }
 
 3、block访问外面变量
  1> block内部可以访问外面的变量
  2> 默认情况下,block内部不能修改外面的局部变量
  3> 给局部变量加上__block,这个局部变量就可以在block内部修改
 
 4、利用typedef定义block类型
 
 typedef int (^MyBlock)(int, int);   以后就可以利用MYBlock这种类型来定义block变量
 
  1> 先定义变量再进行赋值
MyBlock b1,b2;

b1 = ^(int a, int b){
    return a+b;
};

  2> 定义变量同时赋值
MyBlock b3 = ^(int a, int b){
    return a+b;
};

protocol
 1、定义了一个叫MyProtocol的协议
  1> @protocol仅仅是用来声明方法的,声明完方法后等着类来实现
  2> 只要类遵守了这个协议就意味着这个类拥有了这个协议的所有方法声明
  3> 对这个方法可以加个关键字来约束这个方法要不要实现,@required代表必须实现,不实现就会发送警告,默认的就是这个@optional可以不实现
  4> NSObject,它是一个基协议,最根本最基本的协议
    protocol MyProtocol
    @required  必须实现
    - (void)test;
    @optional  可以不实现
    - (void)test2;
    @end

 2、协议的遵守
   1> 只有一个类遵守了某一个协议,就拥有了这份协议中的所有方法声明
   2> : 继承父类
   3> <> 遵守协议
   4> 可以遵守多个协议,在<>里面协议之前用逗号隔开
  @interface Person : NSObject
  @end
   5> 要求obj3保存对象必须遵守Myprotocol
   NSObject *obj3 = [[NSObject alloc] init];
   6> 代表利用set方法设置这个对象的时候,这个对象必须遵守这个协议
  @property (nonatomic, strong) id obj;

 3、协议遵守协议
    一个协议遵守了另外一个协议,就可以拥有这份协议的所有方法声明
  @protocol MyProtocol3

 4、协议的规范
   1> 告诉编译器这两个家伙是个协议,可以取代import
   2> 这样在.m文件里就要包含协议的.h头文件
   3> 遵守原则,先写协议,真正要用的时候再写头文件,提高性能
  @protocol MyProtocol2;
  @protocol MyProtocol3;

总结
 1、协议的定义
 @protocol 协议名称
 // 方法声明列表
 @end
 
 2、如何遵守协议
  1> 类遵守协议
 @interface 类名 :父类名 <协议名称1,协议名称2>
 @end
 
  2> 协议遵守协议
 @protocol 协议名称 <其他协议名称1,其他协议名称2>
 @end
 
 3、.协议中方法声明的关键字
  1> @required(默认)
 要求实现,如果没有实现会发生警告
  2> @optional
 不要求实现,怎样都不会有警告
 
 4、定义一个变量的时候,限制这个变量保存的对象遵守某个协议
  1> 类名<协议名称> *变量名;
  2> id<协议名称> 变量名;
  3> NSObject *obj;
  4> id obj;
 如果没有遵守对应的协议,编译器会警告
 
 5、@property中声明的属性也可以用做一个遵守协议的限制
  1> @property (nonatomic, strong) 类名<协议名称> *属性名
  2> @property (nonatomic, strong) id<协议名称> 属性名
  3> @property (nonatomic, strong) Dog *dog;
  4> @property (nonatomic, strong) id dog;
 
 6、协议可以定义在单独.h文件中,也可以定义在某个类中
  1>如果这个协议只用在某个类中,应该把协议定义在该类中
  2>如果这个协议用在很多类中,就应该定义在单独文件中
 
 7、分类可以定义在单独.h文件中,也可以定义在原来类中
  1> 一般情况下,都是定义在单独文件中
  2> 定义在原来类中的类,只要求能看懂语法

 8、基协议
  1> NSObject是个基类,最根本最基本的类,任何类最终都要继承他
  2> 其实还有个协议,名字也叫NSObject,它是一个基协议,最根本最基本的协议
  3> NSObject协议中声明很多最基本的方法,比如description,retatin、release
  4> 建议每个协议都要遵守基协议

protocol的代理
1> 仅仅告诉编译器Button是一个类
@class Button;
2> 定义一个协议,并且遵守基协议
@protocol ButtonDelegate
3> 监听器的思想,当某个按钮被点击了会告示他哪个按钮被点击了
- (void)onClick:(Button *)but;
@end
4> 使Button 这个类遵守协议
@interface Button : NSObject
- (void)click;
5> 声明中的属性遵守这个协议
@property (nonatomic, retain) id delegate;
@end
@implementation Button
6> 防止unrecognized selector sent to instance 0x100114f10,方法未实现或没有这个方法,判断有没有实现这个方法
- (void)click
{
    如果_delegate实现onClick:方法,就调用这个方法
    if ([_delegate respondsToSelector:@selector(onClick:)])
    {
         按钮被点击了就应该通知监听器,并且告诉监听器哪个按钮被点击了
        [_delegate onClick:self];
    }
    else
    {
        NSLog(@"监听器没有实现onClick:方法");
    }
}
@end

block作为代理回调
#import
1> 仅仅告诉编译器Button是个类
@class Button;
2> 用typedef定义block类型,没有返回值
typedef void (^MyButton)(Button *);

@interface Button : NSObject
3> 定义一个自动生成MyButton类型的setter和getter,生成_btn这个成员变量
@property (nonatomic, assign) MyButton btn;
- (void)click;
@end

@implementation Button
4> 方法实现,用_btn变量调用block内部的代码
- (void)click
{
    调用block
     _btn(self);
}
@end

int main()
{
    @autoreleasepool {
        Button *b = [[[Button alloc] init] autorelease];

 调用setter方法
       b.btn = ^(Button *btn){
       
            NSLog(@"点了这个-%@按钮", btn);
       };
       
 调用方法
       [b click];
 
    }
    return 0;
}

补充:判断stu有没有遵守这个协议
 Student *stu = [[[Student alloc] init] autorelease];
       
        if ([stu conformsToProtocol:@protocol(Study)])
        {
            NSLog(@"%@遵守了这个协议",stu);
        }