zoukankan      html  css  js  c++  java
  • 【IOS学习基础】NSObject.h学习

    一、<NSObject>协议和代理模式

      1.在NSObject.h头文件中,我们可以看到

    // NSObject类是默认遵守<NSObject>协议的
    @interface NSObject <NSObject> {
        Class isa  OBJC_ISA_AVAILABILITY;
    }

    // 往上翻看到NSObject协议的声明
    @protocol NSObject
    /*
      中间一大堆方法的声明
    */
    @end

      然后我就产生疑问了,为什么我们自己定义的协议是这样,后面加上了<NSObject>。为什么我们自己声明的协议需要遵守<NSObject>协议?

      我们都知道,遵守一个协议之后就拥有的该协议中的所有方法的声明。

    @protocol MyProtocol <NSObject>
    /*
      中间一大堆方法的声明
    */
    @end

      2.代理模式

      1> 代理模式:其实就是把自己的事情交给自己的代理去办。A去做一件事,但是他做不到或者他不想做,那么A就去请一个代理B,并且A还要定义一份协议(协议中声明要做的事),只要B遵守了这份协议(表示B有能力帮A完成这些事),就按照这份协议把事情交给B去做。

      有一句话:谁想做什么事,谁就定义协议,并设置一个代理;谁想帮做什么事,谁就遵守协议并实现方法。

      2> 下面以一个例子来说明:

      有一个boss类

    //
    //  Boss.h
    //  代理模式
    //
    //  Created by Silence on 16/1/26.
    //  Copyright © 2016年 Silence. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    // boss有一份协议<ZhuLiDelegate>
    @protocol ZhuLiDelegate <NSObject>
    
    // 助理扫地的方法
    -(void)zhuLiSaoDi;
    
    @end
    
    @interface Boss : NSObject
    
    // 老板有一个助理Deegate,并且这个助理是遵守了ZhuLiDelegate协议的
    // 注意:这里我用的strong修饰的这个delegate(即Boss拥有一个助理的属性Delegate,并且是强引用),但是我并没有在Proxy类中声明一个Boss的属性(即助理有一个老板的属性),老板与助理之间并没有造成循环引用的问题。
    @property (nonatomic,strong)id<ZhuLiDelegate> delegate;
    
    // 老板想要扫地
    -(void)saoDi;
    
    @end
    
    //
    //  Boss.m
    //  代理模式
    //
    //  Created by Silence on 16/1/26.
    //  Copyright © 2016年 Silence. All rights reserved.
    //
    
    #import "Boss.h"
    
    @implementation Boss
    
    // 老板想要扫地(实现)
    -(void)saoDi
    {
        // 老板想要扫地,但是不想自己扫,所以他先查看自己的助理会不会扫地
        if ([self.delegate respondsToSelector:@selector(zhuLiSaoDi)])
        {
            // 如果助理会扫地,那么老板就叫助理去扫地(调用助理的zhuLiSaoDi方法)
            [self.delegate zhuLiSaoDi];
        }
    }
    
    // 说明:respondsToSelector方法,判断某一个对象是否能够响应该方法
    
    @end

    有一个助理类Proxy

    //
    //  Proxy.h
    //  代理模式
    //
    //  Created by Silence on 16/1/26.
    //  Copyright © 2016年 Silence. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    #import "Boss.h"
    
    // 助理类遵守Boss类定义的协议ZhuLiDelegate
    
    @interface Proxy : NSObject<ZhuLiDelegate>
    
    // 那么就表示Proxy有了该协议下的方法声明
    
    @end
    
    //
    //  Proxy.m
    //  代理模式
    //
    //  Created by Silence on 16/1/26.
    //  Copyright © 2016年 Silence. All rights reserved.
    //
    
    #import "Proxy.h"
    
    @implementation Proxy
    
    // 实现协议中的方法
    -(void)zhuLiSaoDi
    {
        NSLog(@"助理去扫地!!!");
    }
    
    @end

    主函数中

    #import <Foundation/Foundation.h>
    #import "Proxy.h"
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            
            Proxy *proxy = [[Proxy alloc] init];
            
            Boss *boss = [[Boss alloc] init];
            // 老板找一个助理对象作为自己的代理
            boss.delegate = proxy;
            
            // 老板想扫地(调用的自己扫地方法,实际是在里面调用的助理扫地的方法)
            [boss saoDi];
        
        }
        return 0;
    }
    
    // 打印
    2016-01-26 14:47:33.817 代理模式[1348:73812] 助理去扫地!!!

      以上就是整个代理模式的实现了。

      3.继续回到 1.中的那个问题,为什么自己定义的协议要遵守<NSObject>协议?

      然后我尝试把上面的<zhuLiDelegate>协议声明处的<NSObject>删掉,编译之后出现错误,如下;

      注意:respondsToSelector方法是在<NSObject>协议中声明的方法。

      这里我们发现self.delegate对象不识别这个方法了,回到delegate声明处:

    @property (nonatomic,strong)id<ZhuLiDelegate> delegate; 
    // 这个delegate遵守了<ZhuLiDlegate>协议,但是我们把
    <ZhuLiDlegate>协议遵守<NSObject>协议的地方删除了,也就表示self.delegate失去了<NSObject>协议中的所有方法声明,所以就导致方法不可识别了
    // 另外,还需明白协议是可以继承了,既然所有NSObject类默认遵守了<NSObject>协议,那么就表示所有继承自NSObject的对象都拥有<NSObject>协议中的方法。除非你像上面一样遵守自己的协议,并且自己的协议并不遵守基协议<NSObject>,这样你的对象就无法调用了<NSObject>中的方法了。

     二、<NSObject>协议的方法

      1.我们都知道,协议中只能声明一大堆方法,但是我们可以看到<NSObject>中有这么几个“属性”

    @property (readonly) NSUInteger hash;
    @property (readonly) Class superclass;
    @property (readonly, copy) NSString *description;
    @optional
    @property (readonly, copy) NSString *debugDescription;

      实际上这些和在分类中增加属性一样,这里只会为你生成相应的set、get方法,并不会生成相应的成员变量(实例变量)

      拿上面的代理模式做测试,我在<zhuLiDelegate>协议,我在其中加了一个name的“属性”(始终记住:生成set、get方法)

      然后在遵守该协议的Proxy类中实现了该set、get方法(具体参考我的上一篇文章”【ios学习基础】OC类的相关”中的在分类实现添加属性),在这里还是贴上代码

    // 假如没有实现相应set、get方法,用.属性访问会崩溃。
    #import
    "Proxy.h" #import <objc/runtime.h> static void *strKey = &strKey; @implementation Proxy -(void)setName:(NSString *)name { objc_setAssociatedObject(self, &strKey, name, OBJC_ASSOCIATION_COPY); } -(NSString *)name { return objc_getAssociatedObject(self, &strKey); } // 实现协议中的方法 -(void)zhuLiSaoDi { NSLog(@"助理去扫地!!!"); } @end

    主函数中

    #import <Foundation/Foundation.h>
    #import "Proxy.h"
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            
            NSObject *obj = [[NSObject alloc] init];
            
            Proxy *proxy = [[Proxy alloc] init];
            
            Boss *boss = [[Boss alloc] init];
            // 老板找一个助理对象作为自己的代理
            boss.delegate = proxy;
            
            proxy.name = @"协议:name属性";
            NSLog(@"%@",proxy.name);
            
            // 老板想扫地(调用的自己扫地方法,实际是在里面调用的助理扫地的方法)
            [boss saoDi];
        }
        return 0;
    }
    
    // 打印
    2016-01-26 15:33:03.625 代理模式[1456:93614] 协议:name属性
    2016-01-26 15:33:03.627 代理模式[1456:93614] 助理去扫地!!!

      2.方法介绍

      1> - (BOOL)isEqual:(id)object;  比较两个对象的地址是否相等

       2> - (id)performSelector:(SEL)aSelector;  调用sSelectopr方法

        - (id)performSelector:(SEL)aSelector withObject:(id)object; 调用sSelectopr方法,传一个参数

        - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2; 调用sSelectopr方法,传两个参数

      这里简单介绍一下SEL类型:

      我们都知道,每一个继承自NSObject对象都有一个isa指针,指向“类的方法列表”(类也有存储空间,既也有地址,一个类在存储空间中仅此一份)

    @interface NSObject <NSObject> {
        Class isa  OBJC_ISA_AVAILABILITY;
    }

      SEL就是对方法的一种包装。包装的SEL类型数据它对应相应的方法地址,找到方法地址就可以调用方法。在内存中每个类的方法都存储在类对象中,每个方法都有一个与之对应的SEL类型的数据,根据一个SEL数据就可以找到对应的方法地址,进而调用方法。

      SEL类型的定义:  typedef struct objc_selector *SEL

      SEL的使用:SEL S1 = @selector(test);   将test方法包装成SEL对象(无参)

             SEL S2= @selector(test:);   将test方法包装成SEL对象(有参)

             SEL S3 = NSSelectorFromString(@"test");   将一个字符串方法转换成为SEL对象 

      3> - (BOOL)isProxy; 判断一个实例是否继承自NSObject,如果返回NO就是继承自NSObject,反之返回YES

      4> - (BOOL)isKindOfClass:(Class)aClass;  判断对象是否属于aClass及其子类

        - (BOOL)isMemberOfClass:(Class)aClass;  判断对象是否属于aClass类

        - (BOOL)conformsToProtocol:(Protocol *)aProtocol;   检查某个对象是否遵守了aProtocol协议

        - (BOOL)respondsToSelector:(SEL)aSelector;  判断对象是否能响应aSelector方法

      5> 内存管理相关

        - (instancetype)retain OBJC_ARC_UNAVAILABLE;

        - (oneway void)release OBJC_ARC_UNAVAILABLE;

        - (instancetype)autorelease OBJC_ARC_UNAVAILABLE;

        - (NSUInteger)retainCount OBJC_ARC_UNAVAILABLE;

    三、NSObject的方法

      1.初始化相关

      + (void)load;  类的头文件被引入就会调用

      + (void)initialize;  类或其子类的第一个方法被调用之前调用

      - (instancetype)init  初始化

      + (instancetype)new OBJC_SWIFT_UNAVAILABLE("use object initializers instead");  创建一个对象

      + (instancetype)allocWithZone:(struct _NSZone *)zone OBJC_SWIFT_UNAVAILABLE("use object initializers instead");  alloc方法内部调用该方法,返回分配的存储空间zone

      + (instancetype)alloc OBJC_SWIFT_UNAVAILABLE("use object initializers instead");  分配存储空间

      - (void)dealloc OBJC_SWIFT_UNAVAILABLE("use 'deinit' to define a de-initializer");  对象销毁时调用

      2.方法相关

      + (BOOL)instancesRespondToSelector:(SEL)aSelector;  判断类是否有aSelector方法

      + (BOOL)conformsToProtocol:(Protocol *)protocol;  判断类是否遵守此协议

      - (IMP)methodForSelector:(SEL)aSelector;  根据一个SEL,得到该方法的IMP(函数指针)

      + (IMP)instanceMethodForSelector:(SEL)aSelector;  类方法,返回的是类方法的真正的函数地址

      - (void)doesNotRecognizeSelector:(SEL)aSelector;  处理接收者无法识别的消息

      - (id)forwardingTargetForSelector:(SEL)aSelector;  当某个对象不能接受某个selector时,将对该selector的调用转发给另一个对象

      3.+ (BOOL)isSubclassOfClass:(Class)aClass;  判断一个类是否是其子类

         + (NSUInteger)hash; 如果isEqual判断两个对象相等,那么两个对象的hash返回值也一定相等。反之hsah值相等,isEqual未必认为两者一样。

         + (Class)superclass; 获得父类类对象

         + (Class)class OBJC_SWIFT_UNAVAILABLE("use 'aClass.self' instead"); 获得本类类对象

         + (NSString *)description;  NSLog打印格式。

         + (NSString *)debugDescription;  打断点时看到的格式。

  • 相关阅读:
    WebService通过SOAP头进行身份验证
    【笔记】NIOS II spi详解
    【笔记】关于NIOS II PIO的几个问题
    【笔记】NIOS II Interval Timer Core详解
    【原创】基于NIOS II SPI的ads8321驱动
    【笔记】MATLAB一些常用函数
    【原创】解决on_chip_memory过小的问题,解决Unable to reach errno ...的问题
    【原创】基于FPGA的等精度测频方法(学习实验)
    【原创】等效采样状态机控制工程(测试通过,待完善说明书)
    【原创】基于NIOS II的ADS1256 SPI驱动
  • 原文地址:https://www.cnblogs.com/silence-wzx/p/5149721.html
Copyright © 2011-2022 走看看