{"id":4592,"date":"2014-03-30T13:44:56","date_gmt":"2014-03-30T13:44:56","guid":{"rendered":"https:\/\/unknownerror.org\/index.php\/2014\/03\/30\/testing-class-equality-in-objective-c-collection-of-common-programming-errors\/"},"modified":"2014-03-30T13:44:56","modified_gmt":"2014-03-30T13:44:56","slug":"testing-class-equality-in-objective-c-collection-of-common-programming-errors","status":"publish","type":"post","link":"https:\/\/unknownerror.org\/index.php\/2014\/03\/30\/testing-class-equality-in-objective-c-collection-of-common-programming-errors\/","title":{"rendered":"&ldquo;Testing Class Equality&rdquo; in Objective-c-Collection of common programming errors"},"content":{"rendered":"<p>There are situations in which people add new classes at runtime. One example is Key Value Observing: when you observe an object the Foundation framework creates a new subclass of the observed object&#8217;s class. This dynamic class behaves in the same way as its superclass, but adds KVO notifications to all of its mutator methods.<\/p>\n<p>The passage you quoted says that the Objective-C runtime can tell this new class apart from the original class. However, because it&#8217;s just an implementation detail of the way KVO is built, you shouldn&#8217;t know or care about it. The developers therefore overrode the <code>-class<\/code> method of their new class, to pretend that objects were still members of the original class.<\/p>\n<p>If you want to check whether two objects are of the same class, you must therefore compare the results of their <code>-class<\/code> methods (which take tricks like KVO into account), instead of using runtime functions.<\/p>\n<p>Here&#8217;s an example:<\/p>\n<pre><code>#import \n#import \n\nint main(int argc, const char * argv[])\n{\n    @autoreleasepool {\n        NSObject *observer = [NSObject new];\n        NSObject *model = [NSObject new];\n\n        [model addObserver: observer forKeyPath: @\"count\" options: 0 context: NULL];\n\n        \/\/using -class methods:\n        NSLog(@\"model is a %@, observer is a %@\", [model class], [observer class]);\n\n        \/\/casting to Class:\n        NSLog(@\"model is a %@, observer is a %@\", *(Class*)model, *(Class*)observer);\n\n        \/\/using the runtime:\n        NSLog(@\"model is a %@, observer is a %@\", object_getClass(model), object_getClass(observer));\n\n        [model removeObserver: observer forKeyPath: @\"count\" context: NULL];\n        [model release];\n        [observer release];\n    }\n    return 0;\n}\n<\/code><\/pre>\n<p>You see that all I&#8217;m doing is creating two objects, telling one of them to observe the other, then finding out what their classes are. Here are the results:<\/p>\n<blockquote>\n<p>2012-06-08 08:37:26.904 Untitled 2[896:707] model is a NSObject, observer is a NSObject<\/p>\n<p>2012-06-08 08:37:26.907 Untitled 2[896:707] model is a NSKVONotifying_NSObject, observer is a NSObject<\/p>\n<p>2012-06-08 08:37:26.907 Untitled 2[896:707] model is a NSKVONotifying_NSObject, observer is a NSObject<\/p>\n<\/blockquote>\n<p>So as the documentation suggests, it&#8217;s only the first case (where we compare <code>-class<\/code>) that does anything the application code could reasonably expect. The other two ways of finding out the class &#8211; asking the runtime, and casting the object pointer to a <code>Class *<\/code> &#8211; both give away implementation details about how KVO has changed the class from underneath us, and mean that the class comparison now won&#8217;t show that the classes are equal.<\/p>\n<p>Because other answers and comments are referring to <code>-isMemberOfClass:<\/code> and <code>-isKindOfClass:<\/code>, I&#8217;ll cover those points too:<\/p>\n<ul>\n<li>\n<p><code>-isKindOfClass:<\/code> is <em>not<\/em> a test for class equality. <code>[object isKindOfClass: aClass]<\/code> is true if <code>object<\/code> is an instance of <code>aClass<\/code> <em>or any of its subclasses<\/em>. Because the passage you&#8217;ve quoted is about class equality, <code>-isKindOfClass:<\/code> is not relevant here. That said, it&#8217;s most often the test that you want to be doing in application code. It&#8217;s more common to care about the answer to &#8220;can I use this object as a <code>Foo<\/code>?&#8221; than &#8220;is this object an instance exactly of <code>Foo<\/code>?&#8221;.<\/p>\n<\/li>\n<li>\n<p><code>-isMemberOfClass:<\/code> is a test for class equality: <code>[object isMemberOfClass: aClass]<\/code> is only true if object is an instance of <code>aClass<\/code>. This test is done using the result of the <code>-class<\/code> method, which means that in this example <code>model<\/code> <em>will<\/em> test positive for <code>[model isMemberOfClass: [NSObject class]]<\/code>.<\/p>\n<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>There are situations in which people add new classes at runtime. One example is Key Value Observing: when you observe an object the Foundation framework creates a new subclass of the observed object&#8217;s class. This dynamic class behaves in the same way as its superclass, but adds KVO notifications to all of its mutator methods. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-4592","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/4592","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/comments?post=4592"}],"version-history":[{"count":0,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/4592\/revisions"}],"wp:attachment":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/media?parent=4592"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/categories?post=4592"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/tags?post=4592"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}