ios开发之 NSObject详解

 NSObject是大部分Objective-C类继承体系的根类。这个类遵循NSObject协议,提供了一些通用的方法,对象通过继承NSObject,可以从其中继承访问运行时的接口,并让对象具备Objective-C对象的基本能力。下面我们就详细的介绍NSObject。

一、使用详解

1.加载及初始化类

1
2
3
4
5
6
7
8
9
/** 运行时加载类或分类调用该方法, 每个类只会调用一次 */
+ (void)load {
  
}
  
/** 类实例化使用前需要先初始化, 一个类调用一次, 如果子类没有实现该方法则会调用父类方法 */
+ (void)initialize {
 
}

注释:
      load`和`initialize`区别在于:`load`是只要类所在文件被引用就会被调用,而`initialize`是在类或者其子类的第一个方法被调用前调用。所以如果类没有被引用进项目,就不会有`load`调用;但即使类文件被引用进来,但是没有使用,那么`initialize`也不会被调用;`load`每个类只会调用一次,`initialize`也只调用一次,但是如果子类没有实现`initialize`方法则会调用父类的方法,因此作为父类的`initialize`方法可能会调用多次。

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

1
2
3
4
5
LXStudent *student =  [LXStudent new];
  
LXStudent *student2 = [[LXStudent alloc] init];
  
LXStudent *student3 = [[LXStudent allocWithZone:nil] init];

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

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

(1)直接调用

1
2
3
4
5
6
// 调用无参无返回值方法(举例)
[student running];<br>
// 调用有参无返回值方法(举例)
[student readingWithText:@"Hello World!"];<br>
// 调用有参有返回值方法 (举例)
NSNumber *sum = [student sumWithNum:@(2) num2:@(3)];

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

(2)使用`performSelector`执行

1
2
3
4
5
6
7
8
9
10
11
12
13
// 先判断对象是否能调用方法,再执行调用方法
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指针调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 创建SEL
SEL runSel = @selector(running);
SEL readSel = NSSelectorFromString(@"readingWithText:");
SEL sumSel = NSSelectorFromString(@"sumWithNum:num2:");
  
// 调用无参无返回值方法
IMP rumImp = [student methodForSelector:runSel];
void (*runFunc)(id, SEL) = (void *)rumImp;
runFunc(student, runSel);
  
// 调用有参无返回值方法
IMP readImp = [[student class] instanceMethodForSelector:readSel];
void (*speakFunc)(id, SEL, NSString *) = (void *)readImp;
speakFunc(student, readSel, @"Hello World");
  
// 调用有参有返回值方法
IMP sumImp = [student methodForSelector:sumSel];
NSNumber *(*sumFunc)(id, SEL, NSNumber *, NSNumber *) = (void *)sumImp;
NSNumber *sum3 = sumFunc(student, sumSel, @(6), @(6));

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

4、复制对象

1
2
3
4
5
6
7
8
9
10
11
// 两个源数组
NSArray *sourceArrayI = [NSArray arrayWithObjects:@"I", @"I", nil];
NSMutableArray *sourceArrayM = [NSMutableArray arrayWithObjects:@"M", @"M", nil];
  
// 两个copy
NSArray *copyArrayI = [sourceArrayI copy];
NSArray *copyArrayM = [sourceArrayM copy];
  
// 两个mutableCopy
NSMutableArray *mutableArrayI = [sourceArrayI mutableCopy];
NSMutableArray *mutableArrayM = [sourceArrayM mutableCopy];

 注释:`copy`拷贝为不可变对象,`mutableCopy`拷贝为可变变量,`copy`和`mutableCopy`都可理解为复制了一个新对象。虽然`copy`对静态对象只是引用计数加1,但是并不影响我们对复制前后的对象进行使用。需要注意的是对于容器对象而言,这两个方法只是复制了容器本身,对容器中包含的对象只是简单的指针引用,并没有深层复制。

5、获取Class

1
2
3
4
5
6
7
// 获取类
Class curClass1 = [student class];
Class curClass2 = [LXStudent class];
  
// 获取父类
Class supClass1 = [student superclass];
Class supClass2 = [LXStudent superclass];

6、判断方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// 初始化对象
LXPerson  *person  =  [LXPerson new];
LXStudent *student =  [LXStudent new];
LXStudent *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 ([LXStudent isSubclassOfClass:[ZMPerson class]]) {
    NSLog(@"LXStudent类是ZMPerson类的子类");
}
  
// 判判断对象是否遵从协议
if ([student conformsToProtocol:@protocol(NSObject)]) {
    NSLog(@"student对象遵循NSObject协议");
}
  
// 判断类是否遵从给定的协议
if ([LXStudent conformsToProtocol:@protocol(NSObject)]) {
    NSLog(@"LXStudent类遵循NSObject协议");
}
  
// 判断对象是否能够调用给定的方法
if ([student respondsToSelector:@selector(running)]) {
    NSLog(@"student对象可以调用‘running’方法");
}
  
// 判断实例是否能够调用给定的方法
if ([LXStudent instancesRespondToSelector:@selector(running)]) {
    NSLog(@"LXStudent类可以调用‘running’方法");
}

二、NSObject.h详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
//
// NSObject.h
// LXHeaderFile
//
// Created by CheYin on 2018/9/4.
// Copyright © 2017年 CheYin. 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; <br>
/** 获取对象hash值, 两对象相等hash值也相等 */
@property (readonly) NSUInteger hash;
  
/** 获取对象的父类 */
@property (readonly) Class superclass;<br>
/** 获取当前对象的类 */
- (Class)class OBJC_SWIFT_UNAVAILABLE("use 'type(of: anObject)' instead");<br>
/** 获取当前对象 */
- (instancetype)self;
  
/** 发送指定的消息给对象, 返回消息执行结果(相当于方法调用) */
- (id)performSelector:(SEL)aSelector;<br>
/** 发送带一个参数的消息给对象, 返回消息执行结果(相当于方法调用) */
- (id)performSelector:(SEL)aSelector withObject:(id)object;<br>
/** 发送带两个参数的消息给对象, 返回消息执行结果(相当于方法调用) */
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
  
/** 判断对象是否继承NSObject */
- (BOOL)isProxy;
  
/** 判断对象是否是给定类或给定类子类的实例 */
- (BOOL)isKindOfClass:(Class)aClass;<br>
/** 判断对象是否是给定类的实例 */
- (BOOL)isMemberOfClass:(Class)aClass;<br>
/** 判断对象是否遵从给定的协议 */
- (BOOL)conformsToProtocol:(Protocol *)aProtocol;
  
/** 判断对象是否能够调用给定的方法 */
- (BOOL)respondsToSelector:(SEL)aSelector;
  
/** 对象引用计数加1, 在MRC下使用 */
- (instancetype)retain OBJC_ARC_UNAVAILABLE;<br>
/** 对象引用计数减1, 在MRC下使用 */
- (oneway void)release OBJC_ARC_UNAVAILABLE;<br>
/** 对象引用计数以推迟方式自动减1, 在MRC下使用 */
- (instancetype)autorelease OBJC_ARC_UNAVAILABLE;<br>
/** 获取对象引用计数, 在MRC下使用 */
- (NSUInteger)retainCount OBJC_ARC_UNAVAILABLE;<br>
/** 获取对象存储空间, 在MRC下使用 */
- (struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;
  
/** 获取对象描述信息 */
@property (readonly, copy) NSString *description;<br>
@optional<br>
/** 获取对象在调试器中的描述信息 */
@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;<br>
/** 类实例化使用前需要先初始化, 一个类调用一次, 如果子类没有实现该方法则会调用父类方法 */
+ (void)initialize;<br>
/** 初始化对象 */
- (instancetype)init<br>
#if NS_ENFORCE_NSOBJECT_DESIGNATED_INITIALIZER
NS_DESIGNATED_INITIALIZER
#endif
;
  
/** 为新对象分配内存空间并初始化, 等于[[NSObject alloc] init] */
+ (instancetype)new OBJC_SWIFT_UNAVAILABLE("use object initializers instead");<br>
/** 为新对象分配内存空间, 参数传nil */
+ (instancetype)allocWithZone:(struct _NSZone *)zone OBJC_SWIFT_UNAVAILABLE("use object initializers instead");<br>
/** 为新对象分配内存空间 */
+ (instancetype)alloc OBJC_SWIFT_UNAVAILABLE("use object initializers instead");<br>
/** 释放对象, 当对象的引用计数为0时会调用此方法 */
- (void)dealloc OBJC_SWIFT_UNAVAILABLE("use 'deinit' to define a de-initializer");<br>
/** 垃圾回收器调用此方法前处理它所使用的内存。 */
- (void)finalize OBJC_DEPRECATED("Objective-C garbage collection is no longer supported");
  
/** 复制为不可变对象 */
- (id)copy;<br>
/** 复制为可变对象 */
- (id)mutableCopy;
  
/** 在指定的内存空间上复制为不可变对象, 在MRC下使用 */
+ (id)copyWithZone:(struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;<br>
/** 在指定的内存空间上复制为可变对象, 在MRC下使用 */
+ (id)mutableCopyWithZone:(struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;
  
/** 判断实例是否能够调用给定的方法 */
+ (BOOL)instancesRespondToSelector:(SEL)aSelector;<br>
/** 判断类是否遵从给定的协议 */
+ (BOOL)conformsToProtocol:(Protocol *)protocol;<br>
/** 获取指向方法实现IMP的指针 */
- (IMP)methodForSelector:(SEL)aSelector;<br>
/** 获取指向实例方法实现IMP的指针 */
+ (IMP)instanceMethodForSelector:(SEL)aSelector;<br>
/** 找不到函数实现的将调用此方法抛出异常 */
- (void)doesNotRecognizeSelector:(SEL)aSelector;
  
/** 返回消息被第一个转发的对象, 对象没有找到SEL的IML时就会执行调用该方法 */
- (id)forwardingTargetForSelector:(SEL)aSelector OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);<br>
/** methodSignatureForSelector:返回不为nil则调用该方法, 可以重写该方法将SEL转发给另一个对象 */
- (void)forwardInvocation:(NSInvocation *)anInvocation OBJC_SWIFT_UNAVAILABLE("");<br>
/** 获取方法签名, 对象没有找到SEL的IML时就会执行调用该方法, 可以重写该方法抛出一个函数的签名,再由forwardInvocation:去执行 */
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE("");
  
/** 获取实例方法签名 */
+ (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE("");
  
/** 允许弱引用标量, 对于所有allowsWeakReference方法返回NO的类都绝对不能使用__weak修饰符 */
- (BOOL)allowsWeakReference UNAVAILABLE_ATTRIBUTE;<br>
/** 保留弱引用变量, 在使用__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);<br>
/** 动态解析一个实例方法, 对象没有找到SEL的IML时就会执行调用该方法, 可以重写该方法给对象添加所需的SEL */
+ (BOOL)resolveInstanceMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
  
/** 获取对象hash值, 两对象相等hash值也相等*/
+ (NSUInteger)hash;<br>
/** 获取对象的父类 */
+ (Class)superclass;<br>
/** 获取类 */
+ (Class)class OBJC_SWIFT_UNAVAILABLE("use 'aClass.self' instead");<br>
/** 获取对象描述信息 */
+ (NSString *)description;<br>
/** 获取对象在调试器中的描述信息 */
+ (NSString *)debugDescription;
  
@end
  
#endif
  
#endif

 







 

posted on   梁飞宇  阅读(1085)  评论(0编辑  收藏  举报

编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示