OC中isKindOfClass和isMemberOfClass的区别

本文详细解析了Objective-C中isKindOfClass与isMemberOfClass两种类型检查方法的区别及应用场景,并通过示例说明如何正确使用这两种方法,特别是针对类簇如NSArray、NSMutableArray的特殊情况。
首先看看两个方法的苹果官方解释:
  • isKindOfClass:
    Returns a Boolean value that indicates whether the receiver is an instance of given class or an instance of any class that inherits from that class. (required)
    这个方法用来判断一个对象是否是指定类或者某个从该类继承类的实例对象。

  • isMemberOfClass:
    Returns a Boolean value that indicates whether the receiver is an instance of a given class. (required)
    这个方法用来判断一个对象是否是指定类的实例对象。

两者区别:
  • isKindOfClass 可以判断某对象是否是某个类的实例对象,这个类和这个类的继承类都可以判断;
  • isMemberOfClass只能判断对象是否是当前类的实例对象。
isMemberOfClass和isKindOfClass的应用举例
UIScrollView *scrollView = [[UIScrollView alloc] init];
if ([scrollView isKindOfClass:[UIView class]]) {
    NSLog(@"scrollView is isKindOfClass UIView");
}

if ([scrollView isKindOfClass:[UIScrollView class]]) {
    NSLog(@"scrollView is isKindOfClass UIScrollView");
}

if ([scrollView isMemberOfClass:[UIView class]]) {
    NSLog(@"scrollView is isMemberOfClass UIView");
}

if ([scrollView isMemberOfClass:[UIScrollView class]]) {
    NSLog(@"scrollView isMemberOfClass UIScrollView");
}

输出结果:
scrollView is isKindOfClass UIView
scrollView is isKindOfClass UIScrollView
scrollView isMemberOfClass UIScrollView

另外需要特别注意的是NSArray、NSMutableArray这样的类:苹果官方文档有这样一段描述

Be careful when using this method on objects represented by a class cluster. Because of the nature of class clusters, the object you get back may not always be the type you expected. If you call a method that returns a class cluster, the exact type returned by the method is the best indicator of what you can do with that object. For example, if a method returns a pointer to an NSArray object, you should not use this method to see if the array is mutable, as shown in the following code:

// DO NOT DO THIS!
if ([myArray isKindOfClass:[NSMutableArray class]])
{
    // Modify the object
}

If you use such constructs in your code, you might think it is alright to modify an object that in reality should not be modified. Doing so might then create problems for other code that expected the object to remain unchanged.

If the receiver is a class object, this method returns YES if aClass is a Class object of the same type, NO otherwise.

测试结果:

NSArray *testArray = [[NSArray alloc] init];
NSMutableArray *testArray2 = [[NSMutableArray alloc] init];
if ([testArray isKindOfClass:[NSArray class]]) {
    NSLog(@"testArray isKindOfClass of NSArray");
}

if ([testArray isMemberOfClass:[NSArray class]]) {
    NSLog(@"testArray isMemberOfClass of NSArray");
}

if ([testArray2 isKindOfClass:[NSMutableArray class]]) {
    NSLog(@"testArray2 isKindOfClass of NSMutableArray");
}

if ([testArray2 isMemberOfClass:[NSMutableArray class]]) {
    NSLog(@"testArray2 isMemberOfClass of NSMutableArray");
}

控制台输出:
testArray isKindOfClass of NSArray
testArray2 isKindOfClass of NSMutableArray

各种查询得出的结论是:NSArray、NSMutableArray属于类簇,使用isMemberOfClass不能取到正确的结果。

原因是:由于类簇的性质,这类对象实际返回的实例有不确定性。
NSArray对象可能会在运行时发现其实运作的是NSCFArray(来自Core Foundation框架(C语言的实现版本),很多Cocoa对象都是如此做桥接的)
总之对于类簇的判断要谨慎。

`isKindOfClass` `isMemberOfClass` 是Objective - C中用于判断对象与类之间关系的方法,以下是对其含义、区别及用法的详细说明: ### 含义 - **isKindOfClass**:用于判断对象是否是指定类的实例,或者是否是该指定类的子类的实例。官方解释为返回一个布尔值,该值指示接收者是否是给定类的实例,或者是从该类继承的任何类的实例[^4]。 - **isMemberOfClass**:用于判断对象是否是指定类的直接实例,不包括该类的子类实例。 ### 区别 - **判断逻辑不同**: - `isKindOfClass` 会检查对象所属的类及其所有父类,只要在继承链中找到匹配的类就返回 `YES`。其内部实现是通过一个循环,从对象的类开始,不断向上遍历其父类,直到找到匹配的类或者到达继承链的顶端(即 `nil`)。示例如下: ```objc + (BOOL)isKindOfClass:(Class)cls { for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) { if (tcls == cls) return YES; } return NO; } ``` - `isMemberOfClass` 只检查对象是否直接属于指定的类,不考虑继承关系。其内部实现是直接比较对象的类指定的类是否相等。示例如下: ```objc + (BOOL)isMemberOfClass:(Class)cls { return object_getClass((id)self) == cls; } ``` - **返回结果不同**: - `isKindOfClass` 在对象是指定类或其子类的实例时返回 `YES`,否则返回 `NO`。例如,`Teacher` 类继承自 `Person` 类,`teacher` 对象使用 `isKindOfClass` 判断是否为 `Person` 类或 `Person` 类的子类时返回 `YES`: ```objc Teacher *teacher = [[Teacher alloc] init]; if ([teacher isKindOfClass:[Person class]]) { NSLog(@"teacher 是 Person类或Person的子类"); } ``` - `isMemberOfClass` 只有在对象是指定类的直接实例时才返回 `YES`,如果对象是指定类子类的实例则返回 `NO`。例如,`UILabel` 继承自 `NSObject`,`label` 对象使用 `isMemberOfClass` 判断是否为 `NSObject` 类的直接实例时返回 `NO`: ```objc UILabel *label = [[UILabel new] autorelease]; if ([label isMemberOfClass:[NSObject class]]) { NSLog(@" is MemberOfClass? NO!"); } ``` ### 用法 - **isKindOfClass**:当需要判断一个对象是否属于某个类或其继承体系时使用。例如,在处理多态的情况下,可以使用 `isKindOfClass` 来判断对象的具体类型,从而执行不同的操作。 ```objc if ([someObject isKindOfClass:[SomeClass class]]) { // 处理 someObject 是 SomeClass 或其子类的情况 } ``` - **isMemberOfClass**:当需要严格判断一个对象是否是某个类的直接实例时使用。例如,在某些情况下,只允许处理某个类的直接实例,而不包括其子类实例,就可以使用 `isMemberOfClass`。 ```objc if ([someObject isMemberOfClass:[SomeSpecificClass class]]) { // 处理 someObject 是 SomeSpecificClass 直接实例的情况 } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值