面试题答案
一键面试使用场景
- id:适用于返回类型不确定,可能是任何类的实例的情况。例如,当一个方法需要返回不同类的实例,取决于运行时条件时。
- instancetype:主要用于返回与接收者相同类型的实例,更适用于工厂方法或初始化方法,这些方法通常返回与类本身相同类型的实例。
类型检查时机
- id:在编译期,编译器仅知道返回值是一个对象,但具体类型未知。类型检查延迟到运行时,通过动态类型识别(Dynamic Type Identification, DTI)来确定实际对象类型。如果在运行时调用了对象不支持的方法,会导致运行时错误(
unrecognized selector sent to instance
)。 - instancetype:在编译期,编译器会根据方法所在的类来确定返回类型。这使得编译器能够在编译期进行更严格的类型检查,捕获更多潜在的类型不匹配错误。
对代码可读性和安全性影响
- id:代码可读性较差,因为无法从返回值类型直接看出实际返回的对象类型。安全性较低,由于运行时才进行类型检查,可能在运行时才发现类型不匹配错误,增加了调试难度。
- instancetype:代码可读性更好,明确表明返回值类型与接收者类型相同。安全性更高,编译期的类型检查可以提前发现许多潜在错误,减少运行时错误的可能性。
代码示例
#import <Foundation/Foundation.h>
@interface Animal : NSObject
+ (id)createAnimal;
+ (instancetype)createSameTypeAnimal;
@end
@implementation Animal
+ (id)createAnimal {
return [[self alloc] init];
}
+ (instancetype)createSameTypeAnimal {
return [[self alloc] init];
}
@end
@interface Dog : Animal
@end
@implementation Dog
@end
@interface Cat : Animal
@end
@implementation Cat
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 使用id返回类型
id animal1 = [Dog createAnimal];
// 这里编译期不会报错,但如果animal1实际不是Cat类型,运行时会崩溃
[(Cat *)animal1 meow;
// 使用instancetype返回类型
Dog *dog = [Dog createSameTypeAnimal];
// 这里如果尝试将返回值赋值给Cat *cat = [Dog createSameTypeAnimal];,编译期会报错
}
return 0;
}
在上述示例中,createAnimal
方法使用id
返回类型,这意味着返回值可以是任何Animal
子类的实例,但在编译期无法确定具体类型。createSameTypeAnimal
方法使用instancetype
返回类型,明确表明返回值类型与调用该方法的类类型相同,编译期会进行更严格的类型检查。