下面程序是否能够执行?为什么?
@interface TPerson : NSObject
- (void)eat;
@end
@implementation TPerson
- (void)eat {
NSLog(@"==TPerson==eat====");
}
@end
TPerson *person = [[TPerson alloc] init];
[person eat];
id pcls = [TPerson class];
void *pp= &pcls;
[(__bridge id)pp eat];
解析,运行程序,控制台输出:
2020-02-21 17:46:54.530375+0800 005---Runtime应用[52965:2000889] ==TPerson==eat====
2020-02-21 17:46:54.530576+0800 005---Runtime应用[52965:2000889] ==TPerson==eat====
可以看到pp
确实正常调用了方法,这是为什么呢?我们先来分析一下,person
调用方法,person
是一个对象,而对象的本质是个结构体,并且第一个元素是isa
,isa
指向的是类对象。实例方法都是存在类中的,person
能够调用方法,也是通过isa
指向了类,从而从类的数据中找到了方法。
再来看看pcls
,pcls
指向的是TPerson
的类对象,而指针pp
又指向的是pcls
的地址,这样也形成了一个指向关系:pp
指向pcls
,而pcls
指向TPerson
的类对象,也就可以正常调用方法了。
我们给TPerson
添加一个属性:
@property (nonatomic, copy) NSString *name;
将eat
的实现改成以下:
- (void)eat {
NSLog(@"==TPerson==eat=====name=%@==", self.name);
}
然后对代码做以下的修改:
// TPerson *person = [[TPerson alloc] init];
// [person eat];
id pcls = [TPerson class];
void *pp= &pcls;
[(__bridge id)pp eat];
运行程序,会发现控制台输出:
2020-02-21 19:23:51.188431+0800 005---Runtime应用[53411:2043433] ==TPerson==eat=====name=<ViewController: 0x7ff70f400760>==
这是为什么呢?然后我们上述注释的代码放开,运行程序,控制台输出:
2020-02-21 19:33:30.325806+0800 005---Runtime应用[53472:2047490] ==TPerson==eat=====name=(null)==
2020-02-21 19:33:30.326163+0800 005---Runtime应用[53472:2047490] ==TPerson==eat=====name=<TPerson: 0x60000129c700>==
在程序运行期间,执行代码就会不停的压栈-出栈操作。由于栈的地址是连续的,pp
又是pcls
的地址。第一次的时候,由于先调用[super viewDidLoad]
,我们的栈里已经压入了ViewController
,当执行[(__bridge id)pp eat]
的时候,需要获取self.name
的值,而name
占用8字节,由于name
本身还没有初始化,也没有值,pp
地址偏移8字节就会获取到之前压入栈里的ViewController
。同理加入TPerson
之后,偏移8字节获取到了TPerson
。
Tips: & 和 *
*
是取值运算符,对地址使用可以获得地址中储存的数值。对于指针a
,*a
表示取a
中的值。
在调用时,*p
是指针p
指向的那个变量,比如:
int a = 5;
int *p = a;
那么p
的值是a
的地址,也就是指针p
指向a
,*p
则等于a
的值,即*p=5
。
&
是地址运算符,对变量使用可以获得该变量的地址。 对于变量b
,&b
表示取b
的地址。
&
是引用,比如:
int a = 5;
int b = &a;
那么这里的b
则引用a
的值,即b=5
,而再给b
赋值:b=10
,a
的值也会变为10。
网友评论