[面试题]
1、属性&成员变量&实例变量的区别
属性 = 带下划线成员变量 + setter + getter 方法
实例变量:(成员变量中的对象变量 就是 实例变量):以实例对象实例化来的,是一种特殊的成员变量
成员变量:写在类声明的大括号中的变量, 我们称之为成员变量。
NSString 是常量类型, 因为不能添加属性,如果定义在类中的{}中,是成员变量
注意: 成员变量不能离开类, 离开类之后就不是成员变量 成员变量不能在定义的同时进行初始化
存储: 堆(当前对象对应的堆的存储空间中)--存储在堆中的数据, 不会被自动释放, 只能程序员手动释放
成员变量中 除去基本数据类型、NSString,其他都是 实例变量(即可以添加属性的成员变量),实例变量主要是判断是不是对象
全局变量:写在函数和大括号外部的变量, 我们称之为全局变量。
作用域: 从定义的那一行开始, 一直到文件末尾
存储: 静态区
程序一启动就会分配存储空间, 直到程序结束才会释放
局部变量:
写在函数或者代码块中的变量, 我们称之为局部变量
作用域: 从定义的那一行开始, 一直到遇到大括号或者return
局部变量可以先定义再初始化, 也可以定义的同时初始化
存储 : 栈
存储在栈中的数据有一个特点, 系统会自动给我们释放
[2、类存在几份?]
由于类的信息在内存中永远只存在一份,所以 类对象只有一份
[3、探索方法的归属问题?]
1、类的加载: 编译过程中是懒加载
2、 实例方法存储在类中,类方法存储在元类中--所以方法永远是归属于类
探索如下:
首先准备工作:创建一个 LGPerson类
@interface LGPerson : NSObject
//类方法
- (void)sayHello;
//实例方法,对象方法
+ (void)sayHappy;
@end
调试调用:
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
// 0x0000000100000000
// LGTeacher *teacher = [LGTeacher alloc];
LGPerson *person = [LGPerson alloc];
Class pClass = object_getClass(person);
//获取该类的所有方法
lgObjc_copyMethodList(pClass);
//通过对象获取类的实例方法
lgInstanceMethod_classToMetaclass(pClass);
//通过对象获取类的类方法
lgClassMethod_classToMetaclass(pClass);
NSLog(@"Hello, World!");
}
return 0;
}
获取类的所有方法:lgObjc_copyMethodList
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);
}
获取类的实例方法:lgInstanceMethod_classToMetaclass
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);
}
获取类的类方法:lgClassMethod_classToMetaclass
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
//
Method method4 = class_getClassMethod(metaClass, @selector(sayHappy));
LGLog(@"%s-%p-%p-%p-%p",__func__,method1,method2,method3,method4);
}
class_getClassMethod 获取类方法
//如果找到元类,就直接返回这个类,没有执行下去的必要,其目的是为了防止元类的无限递归查找
Class getMeta() {
if (isMetaClass()) return (Class)this;
else return this->ISA();
}
so:class_getClassMethod,获取类的方法,其实就是在获取元类的实例方法。
class_getMethodImplementation 在干嘛呢?
查找方法的,函数指针地址,如果没有找到,则实行消息转发
IMP class_getMethodImplementation(Class cls, SEL sel)
{
IMP imp;
if (!cls || !sel) return nil;
imp = lookUpImpOrNil(nil, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER);
// Translate forwarding function to C-callable external version
if (!imp) {
return _objc_msgForward;
}
return imp;
}
总结: 实例方法存储在类中,类方法存储在元类中--所以方法永远是归属于类,
class_getClassMethod,获取类的方法,其实就是在获取元类的实例方法。
[面试题4.oc自省函数,]
-
isKindOfClass&isMemberOfClass示例:类调用2个方法结果:
实例调用2个方法
结果:
isMemberOfClass使用类方法结果解析
1、 NSObject 与 NSObject 的对比,使用 +isKindOfClass BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]]; NSObject 根元类的 superclass 是其本身 NSObject so:re1 = yes; 2、BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]]; NSObject (self->ISA());找到的是根元类 != NSObject so: re2 = NO 3.BOOL re3 = [(id)[LGPerson class] isKindOfClass:[LGPerson class]]; LGPerson 类的self->ISA()找到元类 NSObject,NSObject-》tcls->superclass,= nil; so :re3 = NO; 4. BOOL re4 = [(id)[LGPerson class] isMemberOfClass:[LGPerson class]]; // LGPerson类找到 self->ISA(),根元类NSObject != LGPerson; so re4 = NO,实例方法解析
1、BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]]; NSObject -》[self class],tcls->superclass //传入的实例对象获取的类是NSObject,此实例对象的额父类还是NSObject so :re5=yes 2、BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]]; [self class]->superclass; 传入的实例对象,获取的类是NSObject,实例对象的父类:NSObject so:re6=yes 3、BOOL re7 = [(id)[LGPerson alloc] isKindOfClass:[LGPerson class]]; 传入的实例对象[self class]-》 LGPerson,tcls->superclass -》LGPerson so:re7 = yes 4、BOOL re8 = [(id)[LGPerson alloc] isMemberOfClass:[LGPerson class]]; 传入的实例对象的[self class] ,LGPerson,= LGPerson so re8 = yes