属性&成员变量&实例变量
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
// 属性, 成员变量,实例变量
@interface Pet : NSObject
{ // 成员变量
NSString *name;
// 实例变量, 对象类型,有实例化的。可以添加属性的类型
NSObject *objc;
}
// 属性, 下划线, getter, setter 方法
@property (nonatomic, copy) NSString *nickName;
@end
NS_ASSUME_NONNULL_END
属性 = 带下划线的成员变量 + setter + getter 方法 实例变量: 特殊的成员变量(类的实例化)
方法和属性分析
方法 : sel(方法编号) - imp(函数指针地址)
SEL 相当于书籍目录名称
IMP 相当于书本目录的页面
编译 main.m 文件
clang -rewrite-objc main.m -o main.cpp 把目标文件编译成c++文件
- 这里我们查找我们的编译文件
方法归属分析
OC 方法主要有两种,
实例方法和类方法
- 经过探究,我们知道
实例方法->类中类方法->元类中
1、如何获取类中的实例方法 2、如何获取元类中的类方法
1、如何获取类中的实例方法
首先打开苹果官方文档 developer.apple.com/documentati…
输入 runtime - 查找 Objective-C Functions
Function
class_copyMethodList(_:_:)
Describes the instance methods implemented by a class. // 描述由类实现的实例方法。
根据描述,我们创建 获取类的方法列表 的函数
void lgObjc_copyMethodList(Class pClass){
unsigned int count = 0;
Method *methods = class_copyMethodList(pClass, &count);
for (unsigned int i=0; i < count; i++) {
Method const method = methods[i];
//获取方法名
NSString *key = NSStringFromSelector(method_getName(method));
LGLog(@"Method, name: %@", key);
}
free(methods);
}
- 由当前文档
Discussion我们看到
Discussion
To get the class methods of a class, use class_copyMethodList(object_getClass(cls), &count).
To get the implementations of methods that may be implemented by superclasses, use class_getInstanceMethod(_:_:) or class_getClassMethod(_:_:).
创建获取类的实例方法:
void lgInstanceMethod_classToMetaclass(Class pClass){
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
Method method1 = class_getInstanceMethod(pClass, @selector(sayHello));
Method method2 = class_getInstanceMethod(metaClass, @selector(sayHello));
Method method3 = class_getInstanceMethod(pClass, @selector(sayHappy));
Method method4 = class_getInstanceMethod(metaClass, @selector(sayHappy));
LGLog(@"%s - %p-%p-%p-%p",__func__,method1,method2,method3,method4);
}
创建 获取类的类方法 的函数
void lgClassMethod_classToMetaclass(Class pClass){
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
Method method1 = class_getClassMethod(pClass, @selector(sayHello));
Method method2 = class_getClassMethod(metaClass, @selector(sayHello));
Method method3 = class_getClassMethod(pClass, @selector(sayHappy));
Method method4 = class_getClassMethod(metaClass, @selector(sayHappy));
LGLog(@"%s-%p-%p-%p-%p",__func__,method1,method2,method3,method4);
}
获取方法的具体实现: IMP(函数指针地址)
void lgIMP_classToMetaclass(Class pClass){
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
// - (void)sayHello;
// + (void)sayHappy;
IMP imp1 = class_getMethodImplementation(pClass, @selector(sayHello));
IMP imp2 = class_getMethodImplementation(metaClass, @selector(sayHello));
IMP imp3 = class_getMethodImplementation(pClass, @selector(sayHappy));
IMP imp4 = class_getMethodImplementation(metaClass, @selector(sayHappy));
NSLog(@"%p-%p-%p-%p",imp1,imp2,imp3,imp4);
NSLog(@"%s",__func__);
}
创建测试 对象, 类方法,实例方法
如果文档不清晰,这里我们可以配合 objc 源码 进行调试
- 这里我们可以看到内部实现是获取元类的 实例方法
/***********************************************************************
* class_getClassMethod. Return the class method for the specified
* class and selector.
**********************************************************************/
Method class_getClassMethod(Class cls, SEL sel)
{
if (!cls || !sel) return nil;
return class_getInstanceMethod(cls->getMeta(), sel);
}
- 测试如下:
// 获取类方法
void lgClassMethod_classToMetaclass(Class pClass){
// 实例方法 存储在类中, 类方法,存储在元类中
const char *className = class_getName(pClass);
Class metaClass = objc_getMetaClass(className);
Method method1 = class_getClassMethod(pClass, @selector(sayHello));
Method method2 = class_getClassMethod(metaClass, @selector(sayHello));
// 首先判断, 是否是元类, 不是, 返回 元类, 然后在 元类中查找实例方法
Method method3 = class_getClassMethod(pClass, @selector(sayHappy));
// 元类 为什么有 sayHappy 类方法 0 1
//首先判断 元类 是否是元类,此时是,直接返回元类,然后在元类中查找 sayHappy实例方法,发现有这个实例方法,直接返回找到的实例方法
Method method4 = class_getClassMethod(metaClass, @selector(sayHappy));
LGLog(@"获取类方法: %s:\n method1:%p\n method2:%p \n method3:%p\n method4:%p",__func__,method1,method2,method3,method4);
/*
获取类方法: lgClassMethod_classToMetaclass:
method1:0x0
method2:0x0
method3:0x100003148
method4:0x100003148
*/
}
以上验证了我们的结论: 实例方法 存储在类中, 类方法,存储在元类中
类的判等
- 我们知道如果要判断实例是否是某个类的子类,我们可以使用一下方法
iskindOfClass 和 isMemberOfClass
iskindOfClass
- Returns a Boolean value that indicates whether the receiver is an instance of given class or an instance of any class that inherits from that class.
- 返回一个布尔值,该值指示接收方是给定类的实例还是从该类继承的任何类的实例。
void testKindOfClass() {
/*
// 查找流程: 元类 -> 根元类 -> 根类 -> nil
+ (BOOL)isKindOfClass:(Class)cls {
// 类 vs 元类
// 根元类 vs NSObject
// NSObject vs NSObject
// LGPerson vs 元类 (根元类) (NSObject)
for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
// Calls [obj isKindOfClass]
BOOL
objc_opt_isKindOfClass(id obj, Class otherClass)
{
#if __OBJC2__
if (slowpath(!obj)) return NO;
Class cls = obj->getIsa();
if (fastpath(!cls->hasCustomCore())) {
for (Class tcls = cls; tcls; tcls = tcls->superclass) {
if (tcls == otherClass) {
return YES;
}
}
return NO;
}
#endif
return ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass);
}
// 查找流程: 对象的类 -> 父类 -> 根类 -> nil
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
*/
//
BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]]; //
BOOL re2 = [(id)[LGPerson class] isKindOfClass:[LGPerson class]]; //
BOOL re3 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]]; //
BOOL re4 = [(id)[LGPerson alloc] isKindOfClass:[LGPerson class]]; //
NSLog(@"isKindOfClass:\n re1:%d\n re2:%d\n re3:%d\n re4:%d\n", re1, re2, re3, re4);
}
isMemberOfClass
- Returns a Boolean value that indicates whether the receiver is an instance of a given class.
- 返回一个布尔值,该值指示接收方是否是给定类的实例。
void testMemeberOfClass() {
/*
// 类的元素 与 传入类 对比
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}
// 对象的父类 与 传入类 对比
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
*/
//
BOOL re1 = [(id)[NSObject class] isMemberOfClass:[NSObject class]]; //
BOOL re2 = [(id)[LGPerson class] isMemberOfClass:[LGPerson class]]; //
BOOL re3 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]]; //
BOOL re4 = [(id)[LGPerson alloc] isMemberOfClass:[LGPerson class]]; //
NSLog(@"isMemberOfClass:\n re1:%d\n re2:%d\n re3:%d\n re4:%d\n", re1, re2, re3, re4);
}
isa 走位图
C 语言基础
#define LEN 20
struct names {
char first[20];
char last[20];
};
struct guy {
struct names handle;
char favfood[20];
char job[20];
float income;
};
// 用指针访问成员
+ (void)test2 {
struct guy barney = {
{ "Ewen", "Villard" },
"grilled salmon",
"personality coach",
.income = 68112.00
};
// 声明一个指向结构的指针
struct guy * him; /* 这是一个指向结构的指针 */
// 如果barney是一个guy类型的结构,可以这样写
him = &barney;
// 换句话说,->运算符后面的结构指针和.运算符后面的结构名工作方式 相同(不能写成him.incone,因为him不是结构名)。
NSLog(@"income:%f --- %f", him -> income, barney.income);
/*
这里要着重理解him是一个指针,但是hime->income是该指针所指向结 构的一个成员。
所以在该例中,him->income是一个float类型的变量。
*/
/*
第2种方法是,以这样的顺序指定结构成员的值:
如果him == &fellow[0],
那么*him == fellow[0],
因为&和*是一对互逆运算符。
因此, 可以做以下替代:
fellow[0].income == (*him).income 必须要使用圆括号,因为.运算符比*运算符的优先级高。
总之,如果him是指向guy类型结构barney的指针,下面的关系恒成立:
// 假设 him == &barney
barney.income == (*him).income == him->income
*/
}