1、问题引出
- 打印结果是什么?
// Person.h 文件
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
- (void)print;
+ (void)print;
@end
// Person.m 文件
#import "Person.h"
@implementation Person
- (void)print {
NSLog(@"my name is -- %@",self.name);
}
+ (void)print {
NSLog(@"11");
}
@end
// ViewController.m 文件
#import "ViewController.h"
#import "Person.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSString *test = @"abc";
id cls = [Person class];
void *obj = &cls;
[(__bridge id)obj print];
}
@end
- obj 和普通的person实现对象内存分析对比图
- 这个问题暂时先放一放,不着急回答,请继续往下看。
2、函数栈问题知识补充
- 1、关于函数栈的地址问题
void test() {
long long int a = 1;
long long int b = 2;
long long int c = 3;
long long int d = 4;
NSLog(@"%p %p %p %p", &a,&b,&c,&d);
// 0x7ffee14f7b68 0x7ffee14f7b60 0x7ffee14f7b58 0x7ffee14f7b50
}
从打印结果,可以看出,a~d,4个变量,地址是从高到低排序。
- 在普通的person对象中,内存结构方式如下图所示
- 在当前这种情况下,内存结构方式如下图所示
- 两个图一对比,就可以发现,如果是正常给person的name赋值后,就会通过isa,往后面寻找8个地址,直接找到name指针指向的堆空间
- 在当前这种情况,往后面寻找8个字节地址,找到的是test指针指向的堆空间,误认为test的指针指向的内容就是name指向的内容
结论:最终会调用到test指针指向的堆内存空间,打印结果"my name is – abc"
- 如果代码是这样写的
- (void)viewDidLoad {
[super viewDidLoad];
NSString *test = @"abc";
NSString *test1 = @"123";
id cls = [Person class];
void *obj = &cls;
[(__bridge id)obj print];
NSLog(@"--");
}
- 那么内存分布结构如下图
打印结果,很容易得出:“my name is – 123”
如果只有 [super viewDidLoad];
- (void)viewDidLoad {
[super viewDidLoad];
// 相当于
struct tempCls = {
self,
[ViewController class]
};
objc_msgSendSuper2(abc, sel_registerName("viewDidLoad"));
// 内部实际上会[ViewController class]->getSuperclass
// NSString *test = @"abc";
// NSString *test1 = @"123";
id cls = [Person class];
void *obj = &cls;
[(__bridge id)obj print];
// Person *person = [[Person alloc] init];
// person.name = @"张三";
NSLog(@"--");
}
- 内存结构图如下
所以打印结果如下:my name is – <ViewController: 0x7fad621069d0>