黑马程序员------OC block(代码块)和protocol(协议)

时间:2023-02-11 19:41:06

 ------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ------

一、block代码块

  1.block类型是一个c级别的语法和运行机制,他与标准c函数类似,不同之处在于,它除了有可执行代码以外,还包含了与堆。栈 内存绑定的变量,因此block 对象包含着一组状态数据,这些数据在程序执行是用于对行为产生影响,block被设计为可同时兼容 三种语言 oc c++ c

  

    block 的基本使用

    int^myBlock )(int=int num{    return  }

      1) 无参 无返回值

      定义一个没有参数\没有返回值的block变量,同时赋值。

       void (^block变量名)()=^(){

            代码块的语句

        }

 

       void (^myBlock1)(int)=^( ){

            NSLog(@"xxxx");

        }

        //使用block变量

         myBlock1(); //这样就打印xxxxx 没参数^小括号可以省略

 

       2)有参数无返回值

           void(^变量名)(参数类型及个数)=^(形参列表){

                 代码块语句

             }

             

        viod (^myBlock2)(int,int)=^(int a, int  b){

                 NSLog(@"a+b =%d",a+b);

        }

              myBlock2(3,6);

           //先定义变量,再赋值

          myblock2=^(int x,inty){

            NSLog(@"x*y =%d",x*y);

        }

      3)有参数有返回值

           定义一个有从哪回溯有返回值的block

           int(^myBlock3)(int,int)=^(intx,inty){

                return x+y;

        }

       //使用block ,接受返回值

         int sum =myBlock3 (23,45 );

       //重新给变量赋值

       myblock3=^(int x,inty){

        return x*y;

       }

  2.blocktypedef

   利用typedef定义的block类型(和指向函数的只注重很像)

    typedef void(^myBlock)() :

   格式 : typedef 返回值类型(^新别名)(参数类型列表)

      typedf int (^myBlock1)(int ,int);

    给没有返回值,没有参数的block起一个别名

       myblock是一个类型不在是一个单纯的变量

   typedef void (^myblock)();

 

    myblock f1;

    //block类型的变量

    f1 =^{

                NSLog(@“hellowworld");

     }

         //使用

          f1();

 

    定义有参数 \有返回值的block类型

   int (^block1)(int,int)=^(inta,intb){

               return a=b;

        }

    定义了一个block1的类型 返回值是int  有两个int类型参数

 typedef int(^block1)(int,int);

      block1 b1

       b1 =^(int x,int y){

            return x-y;

        }

       int s=  b1(2,3);

   连续定义多个 block1类型的变量

      block1 n,n2,n2;

 3.block 访问外部变量

       1)在block内部可以访问外部的变量

          当定义block的时候会把外部变量以const 的方式复制一份,存放到block的所在内存中

       2block内部不可以修改外部的变量值

       3)__block 修饰的变量 内部可以修改 应为这里不再以const的方式拷贝

 4.注意:

     1)静态变量和全局变量。在不加 __block 都会直接引用变量地址,也就意味着可以修改变量的值,在没有__block参数的情况下

     2)全局变量block:定义在函数外部的blockglobal 另外如果函数内部的block,但是没有捕捉任何自动变量,那么他也是全局的

     3)栈block 区别,是否引用了外部变量

     4)block 则是对栈block copy得来,对全局block copy不会有任何作用,返回的依然是全局block

 5.block作为函数的返回值

   步骤   1.使用typedef定义一个新类型

        //block起个别名

         typedef int (^newType)(int num1,int num2);

         2.使用新类型作为函数的返回值

         //定义一个返回值是block类型的函数

         newType test4(){}

         3.定义变量接受函数的返回值(block类型)

         4.调用block

    //block类型作为函数的返回值

       newType test(){

 

        newType w1 =^{

         NSLog(@"xxxx");

         NSLog(@"helloword");

     }

        return w1;//返回值

  }

     //定义block类型的变量 接受函数返回的结果

     newType n1 =test();

       //执行block

       n1();

     

 //重新定义一个新的类型 newType2

   typedef int (^newType2)(int,int);

    newType2 test2 {

 

        return^(int a,int b){

               return a+b;

            

            }

 }    

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

       newType2 n2 = test2();

           //调用block

        int s = (23,23);

 7.block的掌握技巧

    1block 结构的快速提示: 输入inlineBlock 

    2)我们在定义block变量的时候,形参类型及个数 这个位置处可以加上形参名

test(^int(int,int)){}

 

实现程序员工作
#import <Foundation/Foundation.h>

 //block类型的变量 workBlock 作为函数的参数
void work( void(^workBlock)() ){

    NSLog(@"起床刷牙");
    NSLog(@"去车站");
    NSLog(@"坐车");
    
    workBlock();//打印其它的
    
    NSLog(@"去车站");
    NSLog(@"坐车回家");
    NSLog(@"吃饭");
    NSLog(@"睡觉");


}
void workday(int n){
    typedef void(^workBlock) ();
    workBlock w;
    switch (n) {
        case 1:
            w=(^{
                NSLog(@"了解项目");
            });
            break;
        case 2:
            w=(^{
                NSLog(@"了解项目");
            });
            break;
        case 3:
            w=(^{
                NSLog(@"了解项目");
            });
            break;
        case 4:
          w=(^{
                NSLog(@"了解项目");
            });
            break;
        case 5:
            w=(^{
                NSLog(@"离职");
            });
            break;
  
        default:
            break;
    }
    //调用函数
    work(w);

}


int main(int argc, const char * argv[]) {
    @autoreleasepool {
       
        workday(5);
        
            return 0;

    }
}


 

二、protocol(协议)

    1.protocol 概念及基本使用

      什么是协议:一些方法的声明 ,一般写到一个.h头文件中

             方法有两种:必须实现的 和选择实现的

      协议的作用: 供其他的类区遵守

              如果一个类遵守了一个协议,就应该实现这个协议宏定义的必须要实现的方法。

    2. 如何定义一个协议

      @protocol xxx <NSObject>  默认的情况下遵守的 NSObject 协议

      @end

     类遵守协议的格式

       1)遵守协议

         先导如入头文件

         @interface  Person :NSObject <xxx>; 

         @end

      2)遵守多个协议

         @interface 类名:NSObject <xxx,aaa ,bbb>;

         @end

      #import <Foundation/Foundation.h>

      //定义一个协议

      //定义协议的流程-->定义协议-->让类遵守这个协议-->实现协议中对应的方法(必须要实现的)

      @protocol basepProtocol <NSObject>

       //声明一些方法

       -(void)eat;

       -(void)run;

       @end

          //Person 遵守这个协议

      @intrface Person :NSObjeect <baseProtocol>

      @end

      @implementation  Person

        -(void)eat{

            NSLog(@"人在吃法饭");

        }

       -(void)run{

         NSLog(@"人在跑步");

         }

      @end

   当我们遵守了某个协议后,就有相当于这个类有了协议中所有的方法声明

 

   3.protocol的其他用法

         protocol的使用注意

           1protocol :就一个用途,用来声明一大堆的方法(不能声明成员变量),不能写实现

           2)只要某个类遵守了这个协议,就拥有了这个协议中的所有方法

           3)只要父类遵守了某个协议,那么子类也遵守 ,实现了协议方法,这些方法可以被子类继承

           4protocol声明的方法可以让任何类区实现 ,protocol就是协议

           5oc中不能继承多个类(单继承)但是能够遵守多个协议。继承( :)协议( < > 

           6)基协议:<NSObject>是基协议,是最根本的协议,其中声明了很多方法。

           7)协议可以遵守协议,一个协议遵守了另一个协议,就可以拥有另一个协议中的方法声明

 4.protocol 中的@reuired @optional

         @required@optional 是协议方法声明中的两个关键字

         他们主要控制方法是否要实现(默认的是@required) ,

          用途 在于程序员之间的交流

        @requried 表示必须要实现的方法

        @optional 可以选择实现方法

 5.protocol  类型限制

    需要一女朋友的条件 定个协议

    housHoldProtocl.h

     @protocol   houseHoldProtocol <NSObject>

     - (void)zuoFan;

     - (void)xiyifu;

     @optional 

      -(void)job;

     @end

   1)使用id存储对象,对象的类型限制

      格式 id<协议名称变量名

       id <Myportocol> obj1;

    //这样写后,表示是给人都满足条件

    所以改为 id<houseHoldProtocol>girl ;

     这样就行限制了 传进来的对象要遵守了协议才可以赋值

  2)对象赋值类型限制

    格式:类名<协议名>*变量名

        Person<hoseHoldProtocol>*p 

           这样必须是人的类的对象才能赋值

 3)对象的关联关系

 

    要求人的狗会算数

      @intterface Person:NSObject 

      //限制了这里传入的狗必须是遵守了dogProtocol的狗

      @property(nonatomic,strong)Dog<dogProtocol>*dog;

      @end

      //狗遵守协议

     @intreface DogNSObject <dogProtocol>

     @end

     

    id instancetype的区别

      1instancetyp只能作为函数或方法的返回值

      2id能作为方法或者函数的返回值、参数类型,也能用来定义一个变量

      3)instancetype 对比id的好处能精确的的限制返回值的具体类型

 6.protocol代理模式设计

     实现 婴儿饿了要吃东西 ,困了要睡觉,

      婴儿类   保姆类

#import <Foundation/Foundation.h>

@protocol baoMuProtocol <NSObject>
- (void)eatToBaby;

- (void)sleepToBaby;
@end
import <Foundation/Foundation.h>
#import "baoMuProtocol.h"
@class baby;
@interface baoMu : NSObject<baoMuProtocol>
@property (nonatomic,weak) baby *baby;
@end
#import "baoMu.h"
#import "baby.h"
@implementation baoMu
- (void)eatToBaby{
    NSLog(@"保姆正在给baby喂奶");

}
- (void)sleepToBaby{
    NSLog(@"保姆正在哄baby睡觉");
}
@end
#import <Foundation/Foundation.h>
@class baoMu;
#import "baoMuProtocol.h"
@interface baby : NSObject
@property (nonatomic,strong) baoMu<baoMuProtocol>*baomu;
- (void)babyWantEat;
- (void)babyWantsleep;

@end
#import "baby.h"
#import "baoMu.h"
@implementation baby
- (void)babyWantEat{
    NSLog(@"baby在哭。。。。");
    [self.baomu eatToBaby];

}
- (void)babyWantsleep{
    NSLog(@"baby在哭。。。。");
    [self.baomu sleepToBaby];
}
@end
#import <Foundation/Foundation.h>
#import "baby.h"
#import "baoMu.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        baoMu *baomu =[[baoMu alloc] init];
        
        baby * ba =[[baby alloc] init];
        ba.baomu = baomu;
        
        [ba  babyWantEat];
        
    }
    return 0;
}


 

protocol代理设计模式概念

   传入对象,代替当前类完成某个功能,称为代理模式。

   

   利用协议实现代理模式的主要思路:

     1)定义一个协议,里面声明代理需需要实现的方法列表。

     2)创建一个代理类,遵守上面的代理协议

     3)在需要代理的类中,定义一个对象类型为id且遵守代理协议的成员变量

     4)在类中调用成员变量_delegate(代理的方法),调用代理的类方法

     5)main.m或其他类文件中,为类的成员变量赋值

   理解应用通过中介找房子

#import <Foundation/Foundation.h>

@protocol findHouseProtocol <NSObject>
- (void)findHouse;
@end
#import <Foundation/Foundation.h>
#import "findHouseProtocol.h"
@interface LinkHome : NSObject<findHouseProtocol>

@end
#import "LinkHome.h"
#import "findHouseProtocol.h"
@implementation LinkHome
- (void)findHouse{
    NSLog(@"链家地产正在给学生找房子");
}
@end

#import <Foundation/Foundation.h>
#import "findHouseProtocol.h"
@interface Student : NSObject
@property (nonatomic ,strong) id<findHouseProtocol>delegate;

-(void)needHouse;
@end
#import "Student.h"
#import "LinkHome.h"
@implementation Student
-(void)needHouse{
    NSLog(@"学生需要一个温暖的家");
    [self.delegate findHouse];
}
@end

#import <Foundation/Foundation.h>
#import "Student.h"
#import "LinkHome.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
       //代理类
        LinkHome *li = [[LinkHome alloc] init];
        
        Student*stu =[[Student alloc] init];
        stu.delegate=li;
           [stu needHouse];
        //代理类 LinKhome
        //代理对象 delegate
        //协议内容 findHouseProtocol
        //协议内容  findHouse
    }
    return 0;
}