然而我已经看不懂ObjC了(゚o゚;;

先大致描述一下问题,然后再直接贴代码吧。

本来以为可以直接获拿到比较原始的Caller的,结果似乎又不行,已经不能理解了(゚o゚;;

在贴代码之前,简要说明一下吧,没有显式传参(好吧,从某个层面上说是传了,知道ObjC消息机制的人应该明白),但是却可以拿到调用者的实例,这里的调用者是指相对来说更“原始”的。

大致调用是这样子的:

ViewController的实例 调用

-[ObjC info] 再调用

-[ObjC speak] 输出的是 ViewController的实例

屏幕快照 2015-01-08 上午12.14.02

问题如下:

  • 为什么在ViewController里能成功拿到比较原始的Caller, 但是在anotherViewController里就不行

还有一个问题看完代码再放可能好一点:

#import "ViewController.h"
#pragma mark
#pragma mark - ObjC
/*!
 * @discussion 下面两个的属性, 它们各自的类型(当然, 至少得是一个指针/引用)是什么都行...
 */
@interface ObjC : NSObject
#if __has_feature(objc_arc)
@property (nonatomic, copy) NSString *caller;
@property (nonatomic, copy) NSString *callerClass;
#else
@property (nonatomic) int *caller;
@property (nonatomic) int *callerClass;
#endif
@end
@implementation ObjC
- (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的实例...
 */
- (void)info{
    [self speak];
}
@end

 

#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...
和View Controller的Custom Class无关
和View Controller的Custom Class无关

 

6 thoughts on “然而我已经看不懂ObjC了(゚o゚;;”

      1. 我这边现在也可以了,那我之前可能是anotherViewController哪里搞错了吧

    1. 最简化的
      在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里面一样的结果了

Leave a Reply

Your email address will not be published. Required fields are marked *

two × 3 =