【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;  打断点时看到的格式。

时间: 2024-12-09 21:47:30

【IOS学习基础】NSObject.h学习的相关文章

云计算学习基础,云计算学习课程

云计算这个概念从提出到今天,差不多10年了.这10年间,云计算取得了飞速的发展与翻天覆地的变化,是继1980年代大型计算机到客户端-服务器的大转变之后的又一次巨变,先是机器越来越小,然后--Duang~还是有很多朋友不了解云计算,那么,什么是云计算?那么先来给你讲个故事吧! 我们先想想一个简单的问题,如果想让计算机变强,怎么办? 那还不简单,加CPU,加内存,加硬盘. 老板,我身上的孔已经被插满了啊! 简单,换更高级的CPU,换新的DDR内存,换新的SSD硬盘. 老板,那个死摩尔定律告诉我,新硬

04-01 集成学习基础

目录 集成学习基础 一.集成学习基础学习目标 二.集成学习基础引入 三.集成学习基础详解 3.1 个体学习器 3.2 Boosting 3.3 Bagging 3.3.1 自助采样法 3.4 结合策略 3.4.1 平均法 3.4.2 投票法 3.4.3 学习法 四.小结 更新.更全的<机器学习>的更新网站,更有python.go.数据结构与算法.爬虫.人工智能教学等着你:https://www.cnblogs.com/nickchen121/ 集成学习基础 集成学习(ensemnle lear

【IOS学习基础】内存管理

1.内存几大区域 1> 栈区:局部变量(基本数据类型.指针变量). 2> 堆区:程序运行的过程中动态分配的存储空间(创建的对象). 3> BSS段:没有初始化的全局变量和静态变量. 4> 数据区:已经初始化的全局变量和静态变量.(字符串常量) 5> 代码段:程序编译后的代码的内容. 2.引用计数器 1> 引用计数器:每个继承自NSObject的对象都有一个引用计数器,用来表示当前对象有几个拥有者. 2> 引用计数器的作用:用来判断对象是否应该回收. 3> 引

转 iOS Core Animation 动画 入门学习(一)基础

iOS Core Animation 动画 入门学习(一)基础 reference:https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreAnimation_guide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40004514 在iOS中,每个view中都自动配置了一个layer,我们不能人为新建,而在Mac OS中,view默认是没有

iOS绘图教程(个人学习总结)

iOS绘图教程:http://www.cocoachina.com/applenews/devnews/2014/0115/7703.html 本篇博文是为了梳理学习过程中得框架,上边链接是cocoachina的教程,更详细一些 iOS支持两套图形API族:Core Graphics/QuartZ 2D 和OpenGL ES 路径用于描述由一序列线和Bézier曲线构成的2D几何形状 Core Graphics中也有一些用于创建简单路径(比如矩形和椭圆形)的便利函数.对于更为复杂的路径,必须用C

python基础教程_学习笔记3:元组

元组 元组不能修改:(可能你已经注意到了:字符串也不能修改.) 创建元组的语法很简单:如果用逗号分隔了一些值,那么你就自动创建了元组. >>> 1,3,'ab' (1, 3, 'ab') 元组也是(大部分时候是)通过圆括号括起来的. >>> (1,3,'13') (1, 3, '13') 空元组可以用没有内容的两个圆括号来表示. 如何实现包括一个值的元组呢? >>> (5) 5 >>> ('ab') 'ab' >>>

php学习基础-文件系统(一) 文件处理,文件权限

一.PHP系统文件处理 /* PHP文件系统处理 * 所有文件处理都是使用系统函数完成的. * 是基于Linux/Unix系统为模型 * * 文件系统处理的作用: * 1. 所有的项目离不开文件处理 * 2. 可以用文件长时间保存数据 * 3. 建立缓存, 服务器中文件操作 * * 文件处理 * 1. 文件类型 * 以Linux为模型的, 在Windows只能获取file, dir或unknow 三种类型 * 在Linux/Unix下, block, char, dir, fifo, file,

零基础如何系统学习Java Web

零基础如何系统学习Java Web? 我来给你说一说 你要下决心,我要转行做开发,这样你才能学成. 你要会打字,我公司原来有一个程序员,打字都是两个手一指禅,身为程序员你一指禅怎么写出的代码,半个月后被辞退了,当然我们还是朋友. 前两个条件都符合了你就可以学了,首先要了解web是什么,一般呢,java web开发无外乎就这么两大类,第一,互联网公司,第二,软件公司.对于互联网公司和软件公司还有一些差别,互联公司是面向广大网民的,会有专门的ui设计,前台开发,后台代码开发,ios开发,androi

python基础教程_学习笔记21:文件和素材

文件和素材 打开文件 open函数用来打开文件,语法如下: open([name[,mode[,buffering]]) open函数使用一个文件名作为唯一的强制参数,然后返回一个文件对象.模式(mode)和缓冲(buffering)参数都是可选的. >>> f=open(r'D:\software(x86)\Python27\README.txt') 如果文件不存在,则出现错误: >>> f=open(r'D:\software(x86)\Python27\READM