iOS面试题解析:奇妙的代码运行结果

0 下载量 168 浏览量 更新于2024-09-03 收藏 196KB PDF 举报
"一道值得深入思考的iOS面试题详解" 这篇内容主要探讨了一道与iOS相关的面试题,涉及Objective-C的类、对象、指针以及Runtime的知识。面试题中,给出的代码看似会有编译错误或运行时崩溃,但实际上却能够正常运行并输出结果。以下是对该面试题的详细解析: 首先,我们来看一下代码的关键部分: ```objc @interface Spark : NSObject @property (nonatomic, copy) NSString *name; @end @implementation Spark -(void)speak{ NSLog(@"My name is: %@", self.name); } @end @implementation ViewController -(void)viewDidLoad { [super viewDidLoad]; id cls = [Spark class]; void *obj = &cls; [(__bridge id)obj speak]; } ``` 面试题中的问题是,这段代码在运行时会有什么结果:编译错误、运行时崩溃还是输出NSLog(即打印"My name is: ..."?)。 初始直觉可能会认为,将`cls`的地址赋值给`void *obj`,然后尝试调用方法,这应该会导致编译错误或运行时崩溃。然而,实际上这段代码并没有引发任何错误,反而正确地执行了`speak`方法,并打印出类名。 **解析原因:** 1. `cls` 是一个指向 `Spark` 类的指针,而 `Spark` 类是继承自 `NSObject` 的,因此它包含了 `isa` 指针,这是 Objective-C 对象的特性。`isa` 指针指向该对象的类元类型。 2. 当我们将 `cls` 转换为 `void *obj` 时,`obj` 只是一个普通的 C 指针,但它仍然存储着 `cls` 的地址,即 `Spark` 类的元类的地址。 3. 使用 `(__bridge id)obj` 这一行代码,我们实际上是在告诉编译器,尽管 `obj` 是 `void *` 类型,但我们要把它当作一个 `id` 类型的对象来处理。Objective-C 的 Runtime 系统允许这样的类型转换,因为所有的 Objective-C 对象都包含 `isa` 指针,即使 `obj` 是通过 `void *` 获取的。 4. 在 Runtime 层面,`obj` 被解释为一个对象,它的 `isa` 指针指向 `Spark` 类的元类。因此,当我们调用 `[(__bridge id)obj speak];` 时,Runtime 系统能够找到 `Spark` 类的 `speak` 方法,并将其执行。 5. 最终,`speak` 方法被调用,由于 `Spark` 类没有设置 `name` 属性,所以输出的是 `My name is: (null)`。 这个面试题考察的是对Objective-C Runtime的理解,特别是类对象、指针转换以及方法调用机制。理解这些概念对于深入iOS开发,尤其是性能优化和内存管理等方面非常重要。开发者需要对Objective-C的动态特性有深入认识,才能在遇到此类问题时准确判断并解决问题。