zoukankan      html  css  js  c++  java
  • OC中分类、类扩展、Block、协议(由协议引出的代理模式)

    一: 分类(Category)

     1>Category的概念:就是在不改变原来类的基础上,为类增加一些方法
        (1,可以为库中定义的类增加方法;2,可以给自己定义的类增加方           法)仅仅是方法哦
          好处:一个类可以有多个文件,编译器会将这些文件按一个类除了,便于团队合作。
     2> 代码格式:
          自定义类中加分类
      
    Person类
    #import "Person.h"
    @interface Person : NSObject
    
    - (void)sayHi;
    
    @end
    
    @implementation Person
    
    - (void)sayHi
    {
        NSLog(@"sayHi----------");
    }
    
    @end

    Person类的分类方法

    #import "Person+study.h"
    @interface Person (study)
    
    - (void)study;
    
    @end
    
    @implementation Person (study)
    
    - (void)study
    {
        NSLog(@"study-------");
    }
    
    @end
           类库中增加分类
    NSString分类方法
    @interface NSString (NSStringWithNum)
    
    - (int)numOfString:(NSString *)string;
    
    @end
    
    @implementation NSString (NSStringWithNum)
    
    - (int)numOfString:(NSString *)string
    {
        int num = 0;
        for (int i = 0; i<string.length; i++) {
            char ch = [string characterAtIndex:i];
            if (ch>'0'&&ch<'9') {
                num++;
            }
        }
        return num;
    }
    
    @end

    Main函数

    #import <Foundation/Foundation.h>
    #import "Person.h"
    #import "Person+study.h"
    #import "NSString+NSStringWithNum.h"
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            
    //        Person *p =[[Person alloc] init];
    //        [p sayHi];
    //        [p study];
            NSString *string = @"hello123word456";
            NSLog(@"%d",[string numOfString:string]);
            
            
            
        }
        return 0;
    }
    3> 注意:
        (1):Category只能增加方法,不能增加成员变量。
          (2):分类可以访问原来类中的成员变量
          (3):如果分类和原类中的方法重名,优先调用分类中的方法,(子类和              父类中,优先调用子类)
          (4):多了分类中重名方法,优先级由编译顺序决定。(后编译的分类方              法先调用)
          
     
    二:类扩展 (匿名分类)class extension
     1> 类扩展概念:为类增添一些私有的成员属性和方法
                            写在.m头文件中
     2> 格式:在.m文件中
    #import "Person.h"
    
    @interface Person ()
    
    @property (nonatomic, copy) NSString *name;
    
    - (void)sayHi;
    
    @end
    
    @implementation Person
    
    - (void)sayHi
    {
        NSLog(@"sayHi-----------");
    }
    
    @end
     
     
    3> 思考:为什么要增加类扩展,将成员属性和方法定义为私有的,定义成公公多好,方便调用
        (1) 私有的成员变量或方法不是不能供外部访问,可以间接访问通过声明 在外部的方法
        (2) 定义成私有的是一种封装的思想,开发者会为外部提供一个公共接口,供外部访问,完成这个公共的方法需要一些其他的方法和属性,而这些方法和属性值,调用者不需要关心,开发者只对公共的方法负责,如果调用者通过其他方法调用了内部私有的方法,开发者对此并不关心。
     
    三:Block数据类型
     1> 概念:Block是一种数据类型,用来存放代码块,它是一种封装的思想,
         用途:可以用来保存一段执行的代码,如多线程中我们要给队列添加任                 务,那么执行的任务可以封装到block代码块中作为参数供函数执               行。
     2> 用法:
     
    #import <Foundation/Foundation.h>
    
    void gotoWork(void(^myBlock)())
    {
        NSLog(@"-----------");
        NSLog(@"????????????");
        NSLog(@",,,,,,,,,,");
        myBlock();
        NSLog(@"99999999999");
        NSLog(@"2222222222");
    }
    
    typedef int (^sumBlock)(int, int);
    int main(int argc, const char * argv[])
    {
        // 按道理说我们在ARC中创建对象的代码必须写在释放池中,因为编译器会将代码加到释放池中
        @autoreleasepool {
            // 用法一:无参无返回值
    //        void (^myBlock)() = ^{
    //            NSLog(@"myBlock--------");
    //        };
    //        myBlock();
            
            // 用法二:有参有返回值
    //        int (^sumBlock)(int, int) = ^(int n, int m){
    //          
    //            return n+m;
    //        };
    //        NSLog(@"%d", sumBlock(3,4));
            
            // 用法三:自定义类型Block使用
    //        sumBlock sumblock = ^(int n, int m){
    //            return n+m;
    //        };
    //        NSLog(@"%d", sumblock(3,4));
            
            // 用法四:访问block代码块外的成员变量,修改block代码块外的成员变量
    //        __block int num = 9;
    //        void (^myBlock)() = ^{
    //            num++;
    //            NSLog(@"%d", num); // 错误,可以访问代码块外的成员变量,因为该成员变量对于代码块
    //                               // 来说是一个全局变量,内部可以访问,但是不能修改,如果想修改的话
    //                               // 可以用(__block)来修饰该成员变量值
    //        };
    //        myBlock();
            // 用法五:Block作为函数的参数使用
    //        gotoWork(^{
    //            
    //            NSLog(@"hello");
    //        });
            // 注意:我们在以后的学习中,Block数据类型经常要作为参数或者任务封装到Block数据类型中
    
        }
        return 0;
    }
     3> 注意:Block访问外部变量

    1)Block内部可以访问外部变量;

    2)默认情况下,Block内部不能修改外部的局部变量

    3)给局部变量加上__block关键字,则这个局部变量可以在block内部进行修改。

    四:协议(Protocol)

     (1)概念

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

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

    3.只要父类遵守了某个协议,那么子类也遵守。

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

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

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

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

    8协议方法声明中的关键字

    (1)required (默认)要求实现,若没有实现则警告但不报错

    (2)Optional 不要求实现

    2>用法:

    经常用在代理方法中,只要某个类遵守一个协议,就可以作为另一个类的代理为该类做事情

    基本用法:

    baby头文件

    #import <Foundation/Foundation.h>
    #import "BabyProtocol.h"
    @class Nurse;
    @interface Baby : NSObject
    
    @property (nonatomic, strong) id<BabyProtocol> delegate;
    @property (nonatomic, assign) int age;
    
    - (void)cry;
    - (void)hungry;
    
    @end

    baby类的.m文件

    #import "Baby.h"
    
    @implementation Baby
    
    - (void)cry
    {
        NSLog(@"%d岁的Baby哭了", self.age);
        [self.delegate noCry:self];
    }
    
    - (void)hungry
    {
        NSLog(@"%d岁的Baby饿了", self.age);
        [self.delegate feed:self];
    }
    
    @end

    Nurse头文件

    #import <Foundation/Foundation.h>
    #import "BabyProtocol.h"
    @interface Nurse : NSObject <BabyProtocol>
    
    @end

    Nurse类的.m文件

    #import "Nurse.h"
    
    @implementation Nurse
    
    - (void)noCry:(Baby *)baby
    {
        NSLog(@"护士哄Baby不要哭");
    }
    
    - (void)feed:(Baby *)baby
    {
        NSLog(@"护士喂Baby吃东西");
    }
    
    @end

    协议头文件

    #import <Foundation/Foundation.h> 
    @class Baby;
    @protocol BabyProtocol <NSObject>
    
    - (void)noCry:(Baby *)baby;
    - (void)feed:(Baby *)baby;
    
    @end

    Main函数

    #import <Foundation/Foundation.h>
    #import "Baby.h"
    #import "Nurse.h"
    
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            
            Baby *baby = [[Baby alloc] init];
            Nurse *nurse = [[Nurse alloc] init];
            baby.delegate = nurse;
    
            baby.age = 3;
            [baby cry];
            [baby hungry];
        }
        return 0;
    }

    3> 注意:

    协议本身写在.h头文件中,但也可以定义在任何地方。当这个协议只有这个类使用遵守时,一般把协议写在这个类里边,当这个协议需要多个类去实现时,就写在外边单独的文件中。

  • 相关阅读:
    在WINDOWS任务计划程序下执行PHP文件 PHP定时功能的实现
    使用Sublime Text 3进行Markdown 编辑+实时预览
    ni_set()函数的使用 以及 post_max_size,upload_max_filesize的修改方法
    CORS跨域的概念与TP5的解决方案
    tp5模型笔记---多对多
    微信小程序 GMT+0800 (中国标准时间) WXSS 文件编译错误
    ESP8266 LUA脚本语言开发: 外设篇-GPIO输入检测
    ESP8266 LUA脚本语言开发: 外设篇-GPIO输出高低电平
    ESP8266 LUA脚本语言开发: 准备工作-LUA文件加载与变量调用
    ESP8266 LUA脚本语言开发: 准备工作-LUA开发说明
  • 原文地址:https://www.cnblogs.com/-boy/p/4088253.html
Copyright © 2011-2022 走看看