美文网首页
iOS 基础篇 - 《NSObject对象详解》

iOS 基础篇 - 《NSObject对象详解》

作者: baiwulong | 来源:发表于2018-04-23 13:25 被阅读338次

NSObject对象简介

NSObject是大部分Objective-C类继承体系的根类。这个类遵循NSObject协议,提供了一些通用的方法,对象通过继承NSObject,可以从其中继承访问运行时的接口,并让对象具备Objective-C对象的基本能力。偷懒了😄原文地址

1、加载及初始化类


/** import导入类或分类时调用该方法, 整个生命周期内都只执行一次而已 */
+ (void)load {} 

/** 每次调用类时调用一次, 如果子类没有实现该方法则会调用父类方法 */
+ (void)initialize {}

loadinitialize区别在于:
load是只要类所在文件被引用就会被调用。(import就会调用
initialize是在类或者其子类的第一个方法被调用前调用。但是如果子类没有实现initialize方法则会调用父类的方法,因此作为父类的initialize方法可能会调用多次。(调用对象的第一个方法前如alloc)

2、分配内存空间及初始化对象

ZMStudent *student = [ZMStudent new];  //常用
ZMStudent *student2 = [[ZMStudent alloc] init];  //常用
ZMStudent *student3 = [[ZMStudent allocWithZone:nil] init];  //不常用

创建新对象时,首先调用alloc为对象分配内存空间,再调用init初始化对象,如[[NSObject alloc] init][NSObject new]等同于[[NSObject alloc] init];关于allocWithZone方法,官方文档解释该方法的参数是被忽略的,正确的做法是传nil或者NULL参数给它。

3、给对象发送消息(执行方法)

(1)直接调用(最常用)

// 调用无参无返回值方法  
[student running];  
// 调用有参无返回值方法  
[student readingWithText:@"Hello World!"];  
// 调用有参有返回值方法  
NSNumber *sum = [student sumWithNum:@(2) num2:@(3)];  

我们通常都采用这种直接调用的方式,给对象发消息执行方法。这种方式调用编译时会自动校验方法、参数、返回值是否正确。因此我们必须在头文件中声明方法的使用。

(2)使用performSelector执行(常用)

// 先判断对象是否能调用方法,再执行调用方法  
if ([student respondsToSelector:@selector(running)]) {  
// 调用无参无返回值方法  
[student performSelector:@selector(running)];  
}  
if ([student respondsToSelector:@selector(readingWithText:)]) {  
// 调用有参无返回值方法  
[student performSelector:@selector(readingWithText:) withObject:@"Hello World"];  
}  
if ([student respondsToSelector:@selector(sumWithNum:num2:)]) {  
// 调用有参有返回值方法  
NSNumber *sum = [student performSelector:@selector(sumWithNum:num2:) withObject:@(2) withObject:@(8)];  
}  

使用performSelector:是运行时系统负责去找方法,在编译时候不做任何校验;因此在使用时必须先使用respondsToSelector:检查对象是否能调用方法,否则可能出现运行崩溃。performSelector:常用于调用运行时添加的方法,即编译时不存在,但是运行时候存在的方法。另外需要注意的是performSelector:系统提供最多接受两个参数的方法,而且参数和返回都是id类型,并不支持基础数据类型(如:int, float等)。

(3)使用IMP指针调用(少用)

// 创建SEL  
SEL runSel = @selector(running);  
SEL readSel = NSSelectorFromString(@"readingWithText:");  
SEL sumSel = NSSelectorFromString(@"sumWithNum:num2:");  
  
// 调用无参无返回值方法  
IMP rumImp = [student methodForSelector:runSel];  
void (*runFunc)(id, SEL) = (voidvoid *)rumImp;  
runFunc(student, runSel);  
  
// 调用有参无返回值方法  
IMP readImp = [[student class] instanceMethodForSelector:readSel];  
void (*speakFunc)(id, SEL, NSString *) = (voidvoid *)readImp;  
speakFunc(student, readSel, @"Hello World");  
  
// 调用有参有返回值方法  
IMP sumImp = [student methodForSelector:sumSel];  
NSNumber *(*sumFunc)(id, SEL, NSNumber *, NSNumber *) = (voidvoid *)sumImp;  
NSNumber *sum3 = sumFunc(student, sumSel, @(6), @(6));  

SEL 是方法的索引。IMP是函数指针,指向方法的地址。SELIMP是一一对应的关系,因此我们可以通过修改对应关系达到运行时方法交换的目的。
创建SEL对象两种方法:
1、使用@selector()创建
2、使用NSSelectorFromString()创建
获取方法IMP指针两种方法:
1、- (IMP)methodForSelector:(SEL)aSelector; 实例方法指针
2、+ (IMP)instanceMethodForSelector:(SEL)aSelector; 类方法指针

4、复制对象

// 两个源数组  
NSArray *sourceArrayI = [NSArray arrayWithObjects:@"I", @"I", nil nil];  
NSMutableArray *sourceArrayM = [NSMutableArray arrayWithObjects:@"M", @"M", nil nil];  
  
// 两个copy  
NSArray *copyArrayI = [sourceArrayI copy];  
NSArray *copyArrayM = [sourceArrayM copy];  
  
// 两个mutableCopy  
NSMutableArray *mutableArrayI = [sourceArrayI mutableCopy];  
NSMutableArray *mutableArrayM = [sourceArrayM mutableCopy]; 

1、一个对象使用copymutabelCopy方法可以创建对象的副本
copy - 需要先实现NSCoppying协议,创建的是不可变副本(如NSString、NSArray、NSDictionary
2、mutabelCopy - 需要先实现NSMutabelCopying协议,创建的是可变副本,(如NSMutabelString、NSMutabelArray、NSMutabelDictionary
深复制:内容拷贝,源对象和副本指向的是不同的两个对象。源对象引用计数器不变,副本计数器设置为1
3、浅复制:指针拷贝,源对象和副本指向的是同一个对象。对象的引用计数器+1,其实相当于做了一次retain操作
4、只有不可变对象创建不可变副本(copy)才是浅拷贝,其他都是深拷贝

5、获取Class

// 获取类  
Class curClass1 = [student class];  //获取对象的类
Class curClass2 = [ZMStudent class];  //获取类的父类
// 获取父类  
Class supClass1 = [student superclass];  
Class supClass2 = [ZMStudent superclass];  

6、判断方法

// 初始化对象  
ZMPerson *person = [ZMPerson new];  
ZMStudent *student = [ZMStudent new];  
ZMStudent *student2 = student;  
  
// 判断对象是否继承NSObject  
if ([student isProxy]) {  
NSLog(@"student对象是继承NSObject类");  
}  
  
// 判断两个对象是否相等  
if ([student isEqual:student2]) {  
NSLog(@"student对象与student2对象相等");  
}  
  
// 判断对象是否是指定类  
if ([person isKindOfClass:[ZMPerson class]]) {  
NSLog(@"person对象是ZMPerson类");  
}  
  
// 判断对象是否是指定类或子类  
if ([student isKindOfClass:[ZMPerson class]]) {  
NSLog(@"student对象是ZMPerson类的子类");  
}  
  
// 判断是否是另一个类的子类  
if ([ZMStudent isSubclassOfClass:[ZMPerson class]]) {  
NSLog(@"ZMStudent类是ZMPerson类的子类");  
}  
  
// 判判断对象是否遵从协议  
if ([student conformsToProtocol:@protocol(NSObject)]) {  
NSLog(@"student对象遵循NSObject协议");  
}  
  
// 判断类是否遵从给定的协议  
if ([ZMStudent conformsToProtocol:@protocol(NSObject)]) {  
NSLog(@"ZMStudent类遵循NSObject协议");  
}  
  
// 判断对象是否能够调用给定的方法  
if ([student respondsToSelector:@selector(running)]) {  
NSLog(@"student对象可以调用‘running’方法");  
}  
  
// 判断实例是否能够调用给定的方法  
if ([ZMStudent instancesRespondToSelector:@selector(running)]) {  
NSLog(@"ZMStudent类可以调用‘running’方法");  
}  

NSObject.h详解



//  
// NSObject.h  
// ZMHeaderFile  
//  
// Created by ZengZhiming on 2017/4/17.  
// Copyright © 2017年 菜鸟基地. All rights reserved.  
//  
// 详解 NSObject.h  
// Version iOS 10.3  
//  
  
#ifndef _OBJC_NSOBJECT_H_  
#define _OBJC_NSOBJECT_H_  
  
#if __OBJC__  
  
#include <objc/objc.h>  
#include <objc/NSObjCRuntime.h>  
  
@class NSString, NSMethodSignature, NSInvocation;  
  
#pragma mark - 协议部分  
  
@protocol NSObject  
  
/** 判断两个对象是否相等, 如相等返回YES, 否则返回NO */  
- (BOOL)isEqual:(id)object;  
/** 获取对象hash值, 两对象相等hash值也相等 */  
@property (readonly) NSUInteger hash;  
  
/** 获取对象的父类 */  
@property (readonly) Class superclass;  
/** 获取当前对象的类 */  
- (Class)class OBJC_SWIFT_UNAVAILABLE("use 'type(of: anObject)' instead");  
/** 获取当前对象 */  
- (instancetype)self;  
  
/** 发送指定的消息给对象, 返回消息执行结果(相当于方法调用) */  
- (id)performSelector:(SEL)aSelector;  
/** 发送带一个参数的消息给对象, 返回消息执行结果(相当于方法调用) */  
- (id)performSelector:(SEL)aSelector withObject:(id)object;  
/** 发送带两个参数的消息给对象, 返回消息执行结果(相当于方法调用) */  
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;  
  
/** 判断对象是否继承NSObject */  
- (BOOL)isProxy;  
  
/** 判断对象是否是给定类或给定类子类的实例 */  
- (BOOL)isKindOfClass:(Class)aClass;  
/** 判断对象是否是给定类的实例 */  
- (BOOL)isMemberOfClass:(Class)aClass;  
/** 判断对象是否遵从给定的协议 */  
- (BOOL)conformsToProtocol:(Protocol *)aProtocol;  
  
/** 判断对象是否能够调用给定的方法 */  
- (BOOL)respondsToSelector:(SEL)aSelector;  
  
/** 对象引用计数加1, 在MRC下使用 */  
- (instancetype)retain OBJC_ARC_UNAVAILABLE;  
/** 对象引用计数减1, 在MRC下使用 */  
- (oneway void)release OBJC_ARC_UNAVAILABLE;  
/** 对象引用计数以推迟方式自动减1, 在MRC下使用 */  
- (instancetype)autorelease OBJC_ARC_UNAVAILABLE;  
/** 获取对象引用计数, 在MRC下使用 */  
- (NSUInteger)retainCount OBJC_ARC_UNAVAILABLE;  
/** 获取对象存储空间, 在MRC下使用 */  
- (struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;  
  
/** 获取对象描述信息 */  
@property (readonly, copy) NSString *description;  
@optional  
/** 获取对象在调试器中的描述信息 */  
@property (readonly, copy) NSString *debugDescription;  
  
@end  
  
#pragma mark - 类部分  
  
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0)  
OBJC_ROOT_CLASS  
OBJC_EXPORT  
@interface NSObject <NSObject> {  
Class isa OBJC_ISA_AVAILABILITY;  
}  
  
/** 运行时加载类或分类调用该方法, 每个类只会调用一次 */  
+ (void)load;  
/** 类实例化使用前需要先初始化, 一个类调用一次, 如果子类没有实现该方法则会调用父类方法 */  
+ (void)initialize;  
/** 初始化对象 */  
- (instancetype)init  
#if NS_ENFORCE_NSOBJECT_DESIGNATED_INITIALIZER  
NS_DESIGNATED_INITIALIZER  
#endif  
;  
  
/** 为新对象分配内存空间并初始化, 等于[[NSObject alloc] init] */  
+ (instancetype)new OBJC_SWIFT_UNAVAILABLE("use object initializers instead");  
/** 为新对象分配内存空间, 参数传nil */  
+ (instancetype)allocWithZone:(struct _NSZone *)zone OBJC_SWIFT_UNAVAILABLE("use object initializers instead");  
/** 为新对象分配内存空间 */  
+ (instancetype)alloc OBJC_SWIFT_UNAVAILABLE("use object initializers instead");  
/** 释放对象, 当对象的引用计数为0时会调用此方法 */  
- (void)dealloc OBJC_SWIFT_UNAVAILABLE("use 'deinit' to define a de-initializer");  
/** 垃圾回收器调用此方法前处理它所使用的内存。 */  
- (void)finalize OBJC_DEPRECATED("Objective-C garbage collection is no longer supported");  
  
/** 复制为不可变对象 */  
- (id)copy;  
/** 复制为可变对象 */  
- (id)mutableCopy;  
  
/** 在指定的内存空间上复制为不可变对象, 在MRC下使用 */  
+ (id)copyWithZone:(struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;  
/** 在指定的内存空间上复制为可变对象, 在MRC下使用 */  
+ (id)mutableCopyWithZone:(struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;  
  
/** 判断实例是否能够调用给定的方法 */  
+ (BOOL)instancesRespondToSelector:(SEL)aSelector;  
/** 判断类是否遵从给定的协议 */  
+ (BOOL)conformsToProtocol:(Protocol *)protocol;  
/** 获取指向方法实现IMP的指针 */  
- (IMP)methodForSelector:(SEL)aSelector;  
/** 获取指向实例方法实现IMP的指针 */  
+ (IMP)instanceMethodForSelector:(SEL)aSelector;  
/** 找不到函数实现的将调用此方法抛出异常 */  
- (void)doesNotRecognizeSelector:(SEL)aSelector;  
  
/** 返回消息被第一个转发的对象, 对象没有找到SEL的IML时就会执行调用该方法 */  
- (id)forwardingTargetForSelector:(SEL)aSelector OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);  
/** methodSignatureForSelector:返回不为nil则调用该方法, 可以重写该方法将SEL转发给另一个对象 */  
- (void)forwardInvocation:(NSInvocation *)anInvocation OBJC_SWIFT_UNAVAILABLE("");  
/** 获取方法签名, 对象没有找到SEL的IML时就会执行调用该方法, 可以重写该方法抛出一个函数的签名,再由forwardInvocation:去执行 */  
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE("");  
  
/** 获取实例方法签名 */  
+ (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE("");  
  
/** 允许弱引用标量, 对于所有allowsWeakReference方法返回NO的类都绝对不能使用__weak修饰符 */  
- (BOOL)allowsWeakReference UNAVAILABLE_ATTRIBUTE;  
/** 保留弱引用变量, 在使用__weak修饰符的变量时, 当被赋值对象的retainWeakReference方法返回NO的情况下, 该变量将使用“nil” */  
- (BOOL)retainWeakReference UNAVAILABLE_ATTRIBUTE;  
  
/** 判断是否是另一个类的子类 */  
+ (BOOL)isSubclassOfClass:(Class)aClass;  
  
/** 动态解析一个类方法 */  
+ (BOOL)resolveClassMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);  
/** 动态解析一个实例方法, 对象没有找到SEL的IML时就会执行调用该方法, 可以重写该方法给对象添加所需的SEL */  
+ (BOOL)resolveInstanceMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);  
  
/** 获取对象hash值, 两对象相等hash值也相等*/  
+ (NSUInteger)hash;  
/** 获取对象的父类 */  
+ (Class)superclass;  
/** 获取类 */  
+ (Class)class OBJC_SWIFT_UNAVAILABLE("use 'aClass.self' instead");  
/** 获取对象描述信息 */  
+ (NSString *)description;  
/** 获取对象在调试器中的描述信息 */  
+ (NSString *)debugDescription;  
  
@end  
  
#endif  
  
#endif  

相关文章

  • iOS 基础篇 - 《NSObject对象详解》

    NSObject对象简介 NSObject是大部分Objective-C类继承体系的根类。这个类遵循NSObjec...

  • 一文详解 NSObject 对象的内存布局

    一文详解 NSObject 对象的内存布局一文详解 NSObject 对象的内存布局

  • IOS基础:NSObject对象模型解析

    原创:知识点总结性文章创作不易,请珍惜,之后会持续更新,不断完善个人比较喜欢做笔记和写总结,毕竟好记性不如烂笔头哈...

  • iOS 开发者证书详解(推送篇)

    推出iOS 开发者证书详解(基础篇)后一直忙于公司的持续集成环境的配置、推广使用。iOS 开发者证书详解(推送篇)...

  • iOS原理(一)----OC对象结构

    iOS原理(一)----OC对象结构 创建一个普通的NSObject对象如下: NSObject的声明如下: 查看...

  • iOS NSObject详解

    前言 官方对于NSObject的解释如下:The root class of most Objective-C c...

  • iOS-isa指针

    iOS所有对象的最终的父类都是NSObject,NSProxy不是NSObject的子类。NSObject有一个数...

  • iOS签名机制

    应用签名的原理iOS APP签名机制详解iOS逆向之旅(基础篇) — App的签名机制【Xcode是如何将App安...

  • iOS 详解NSObject协议

    协议就是一组接口的集合,遵守一个协议之后就拥有的该协议中所有方法的声明。NSObject这个类遵守了NSObjec...

  • OC--KVC

    参考:iOS开发技巧系列---详解KVC(我告诉你KVC的一切)KVC原理剖析 NSObject(NSKeyVal...

网友评论

      本文标题:iOS 基础篇 - 《NSObject对象详解》

      本文链接:https://www.haomeiwen.com/subject/lsuklftx.html