美文网首页iOS DeveloperDev.DeepiOS develop
神经病院objc runtime入院考试(拓展题)

神经病院objc runtime入院考试(拓展题)

作者: 酷酷的哀殿 | 来源:发表于2016-09-19 13:37 被阅读1285次

原题作者:@Sunny
原题地址: 神经病院objc runtime入院考试

今天早上看到有一位好友 冰霜 写了一篇文章 神经病院Objective-C Runtime入院第一天—isa和Class

看着有些手痒,特地添加了一道拓展题,欢迎 iOS 的小伙伴们参加考试。

拓展题:添加或修改一行代码,使得下面的输出为
my name's Sark

@interface Sark : NSObject
@property (nonatomic, copy) NSString *name;
- (void)speak;
@end
@implementation Sark
- (void)speak {
  NSLog(@"my name's %@", self.name);
}
@end
@implementation ViewController
- (void)viewDidLoad {
  [super viewDidLoad];
  id cls = [Sark class];
  void *obj = &cls;
  [(__bridge id)obj speak];
}
@end

相关文章

网友评论

  • DrunkenMouse:我在这里说下我的思路与答案吧,另外多谢哀殿下的讲解。这题想问的应该是关于栈中数据的存储于读取。当viewDidLoad方法调用时,栈中存储入参的顺序是由高到低的,头两个是隐藏参数为self、cmd,之后才为自己手动传入的参数。其中self是自身,cmd我一开始一直以为是选择子,但貌似是错的。而当方法运行读取到self.name时,本质上是self指针(指向自身的指针)向高位移动,移动到存储name属性的地址后读取地址中的内容。参考霜40的资料应该是只移动一个指针的位置,也就是32位。所以只要在self与cmd中间插入指向[Sark class]的数据即可,让self指针偏移后指向的是插入的数据即可。那么,怎么插入那?我想到的只有消息传递的objc_msgSend,具体写法如下:((void (*)(id,id,SEL))(void *)objc_msgSend)((__bridge id)obj,[Sark class],NSSelectorFromString(@"speak")); 然后一运行,崩了。没错,直接崩了。然后我改了一下SEL的位置((void (*)(id,SEL,id))(void *)objc_msgSend)((__bridge id)obj,NSSelectorFromString(@"speak"),[Sark class]); 结果输出还是ViewController的地址。

    最后我的答案是把self.name 改成 [Sark class] 。具体如下:NSLog(@"my name's %@", [Sark class]); :broken_heart:
    酷酷的哀殿: @DrunkenMouse
    快了
    DrunkenMouse:@酷酷的哀殿 哀殿下,啥时候讲解下答案啊- -
    酷酷的哀殿:@DrunkenMouse 脑洞大开啊
  • Usan:好
  • DrunkenMouse:之前四题写出来了,这题还真没整出来。。
    酷酷的哀殿: @DrunkenMouse 没有回答到点上,从汇编层面考虑
    DrunkenMouse:@酷酷的哀殿 栈、堆是存储数据的位置,OC方法调用通过消息传递,实例变量通过get方法的IMP。是不是这些?
    酷酷的哀殿: @DrunkenMouse 考察了三个知识,栈,OC 方法的调用约定,OC 中类的实例变量获取
  • 张xd:
    id cls1 = [Sark class];
    酷酷的哀殿: @张xd 但是明白原理的人仍然不多
    张xd:@酷酷的哀殿 sunnyxx多少年前的题了,哈哈
    酷酷的哀殿:@张xd 赞
  • 天空中的球:方法一、 修改:NSLog(@"my name's %@", NSStringFromClass([Sark class]));
    方法二、 添加 [(__bridge id)obj setName:NSStringFromClass([Sark class])];
    酷酷的哀殿: @天空中的球 方向偏了,如果你能明白原来那道题的答案,就能知道我的出题本意了
    天空中的球:@酷酷的哀殿
    要不再次修改
    1、NSLog(@"my name's %@", [super class]);
    2、NSLog(@"my name's %@", [self class]);
    或者再次添加
    1、[(__bridge id)obj setValue:@"Sark" forKey:@"name"];
    2、((void (*)(id, SEL,NSString *))objc_msgSend)((__bridge id)obj, @selector(setName:),@"Sark");
    其他的暂时没想到,求指点, :smile:

    酷酷的哀殿: @天空中的球 思路不错,有其它方案吗?

本文标题:神经病院objc runtime入院考试(拓展题)

本文链接:https://www.haomeiwen.com/subject/krqnettx.html