先大致描述一下问题,然后再直接贴代码吧。
本来以为可以直接获拿到比较原始的Caller的,结果似乎又不行,已经不能理解了(゚o゚;;
在贴代码之前,简要说明一下吧,没有显式传参(好吧,从某个层面上说是传了,知道ObjC消息机制的人应该明白),但是却可以拿到调用者的实例,这里的调用者是指相对来说更“原始”的。
大致调用是这样子的:
ViewController的实例 调用
-[ObjC info] 再调用
-[ObjC speak] 输出的是 ViewController的实例
问题如下:
- 为什么在ViewController里能成功拿到比较原始的Caller, 但是在anotherViewController里就不行
还有一个问题看完代码再放可能好一点:
#pragma mark - ObjC
* @discussion 下面两个的属性, 它们各自的类型(当然, 至少得是一个指针/引用)是什么都行...
*/
@property (nonatomic, copy) NSString *caller;
@property (nonatomic, copy) NSString *callerClass;
#else
@property (nonatomic) int *caller;
@property (nonatomic) int *callerClass;
#endif
- (void)speak{
NSLog(@"%@",self.caller);
NSLog(@"%@",self.callerClass);
#if __has_feature(objc_arc)
[[(id)(self.caller) view] setBackgroundColor:[UIColorblackColor]];
#else
[[reinterpret_cast<UIView *>(self.caller) view] setBackgroundColor:[UIColor blackColor]];
#endif
}
* @discussion 通过info来调用speak方法, 但是还是能拿到UIViewController的实例...
*/
[self speak];
}
#pragma mark
#pragma mark - anotherViewController
@interface anotherViewController : UIViewController @end
@implementation anotherViewController
- (void)viewDidLoad{
[(__bridge id)((void *)({id cls = [ObjC class];&cls;})) info];
// 指针指向ClassObject, 故能够正常走Objetive-C的消息机制
}
@end
#pragma mark
#pragma mark - ViewController
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 下面两个的先后顺序不影响, 只测试其中一种, 另一个注释掉也是一样的结果
[(__bridge id)((void *)({id cls = [ObjC class];&cls;})) info];
// 指针指向ClassObject, 故能够正常走Objetive-C的消息机制
[self presentViewController:[[anotherViewController alloc] init] animated:YES completion:nil];
}
@end
看了第一个问题和代码之后, 你或许会说, 可能是因为storyboard里初始化的是ViewController类而不是anotherViewController类,所以不行。又或者会说,各个变量入栈顺序为(self, _cmd, self.class, self, receiver(匿名变量)),遂取.caller和.callerClass是随栈底地址的receiver往上走,取到了self和self.class。但是,问题来了, 挖掘机技术哪家强
- 在Interface Builder中把View Controller的Class从ViewController改为anotherViewController之后还是会Crash...
按照楼主的代码建了个工程, anotherViewController也是可以的呀!
诶?我这边的话,会直接crash
我这边现在也可以了,那我之前可能是anotherViewController哪里搞错了吧
你的问题描述得有点绕,示例代码能再简化一点么?
最简化的
在Xcode中新建一个Single View Application的工程,然后在ViewController.m里面添加:
@interface ObjC : NSObject
@property (nonatomic, copy) NSString *caller;
@property (nonatomic, copy) NSString *callerClass;
@end
@implementation ObjC
- (void)speak{
NSLog(@"%@",self.caller);
NSLog(@"%@",self.callerClass);
[[(id)(self.caller) view] setBackgroundColor:[UIColor blackColor]];
}
@end
然后在-[ViewController viewDidLoad]里面调用:
id cls = [ObjC class];
void *obj = &cls;;
[(__bridge id)obj speak];
就能得到和post里面一样的结果了
好像依赖于is_a指针,然后跟栈上数据的顺序有关