Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Reverse-engineered implementation of -[NSString isEqual:] and -[NSString isEqualToString:]
/*
* Most NSString instances will actually be __NSCFString instances, so here are both NSString and __NSCFString implementations.
* If you know how to create an NSString instance whose class is actually NSString please let me know.
* Other possible concrete subclasses of NSString are: NSConstantString, __NSCFConstantString, NSPathStore2, NSSimpleCString and __NSLocalizedString.
*/
// CoreFoundation.framework 635.19.0 (Mac OS X 10.7.3)
@implementation NSObject
- (BOOL) isNSString__
{
return NO;
}
@end
@implementation __NSCFString
static CFStringEncoding enc = 0;
- (BOOL) isNSString__
{
return YES;
}
- (BOOL) isEqual:(id)string
{
if (self == string)
{
return YES;
}
else if (string == nil)
{
return NO
}
else
{
Class stringClass = [string class];
Class nscfStringClass = objc_lookUpClass("__NSCFString");
if (stringClass == nscfStringClass || class_getSuperclass(stringClass) == nscfStringClass)
{
if (enc == kCFStringEncodingInvalidId)
enc = CFStringGetSystemEncoding();
const char *selfCString = CFStringGetCStringPtr(self, enc);
if (enc == kCFStringEncodingInvalidId)
enc = CFStringGetSystemEncoding();
const char *argCString = CFStringGetCStringPtr(string, enc);
if (selfCString != NULL && argCString != NULL)
{
CFIndex length = _CFStringGetLength2(self);
if (length == _CFStringGetLength2(string))
{
return memcmp(selfCString, argCString, length) == 0;
}
else
{
return NO;
}
}
}
}
if (![string isNSString__])
return NO;
// Eventually calls __CFStringEqual whose implementation is available at http://opensource.apple.com/source/CF/CF-635.19/CFString.c
return CFEqual(self, string);
}
- (BOOL) isEqualToString:(NSString *)string
{
if (self == string)
{
return YES;
}
else if (string == nil)
{
return NO
}
else
{
Class stringClass = [string class];
Class nscfStringClass = objc_lookUpClass("__NSCFString");
if (stringClass == nscfStringClass || class_getSuperclass(stringClass) == nscfStringClass)
{
if (enc == kCFStringEncodingInvalidId)
enc = CFStringGetSystemEncoding();
const char *selfCString = CFStringGetCStringPtr(self, enc);
if (enc == kCFStringEncodingInvalidId)
enc = CFStringGetSystemEncoding();
const char *argCString = CFStringGetCStringPtr(string, enc);
if (selfCString != NULL && argCString != NULL)
{
CFIndex length = _CFStringGetLength2(self);
if (length == _CFStringGetLength2(string))
{
return memcmp(selfCString, argCString, length) == 0;
}
else
{
return NO;
}
}
}
}
// Eventually calls __CFStringEqual whose implementation is available at http://opensource.apple.com/source/CF/CF-635.19/CFString.c
return CFEqual(self, string);
}
@end
// Foundation.framework 833.24.0 (Mac OS X 10.7.3)
@implementation NSString
- (BOOL) isNSString__
{
return YES;
}
- (BOOL) isEqual:(id)string
{
if ([string isNSString__])
return [self isEqualToString:string];
else
return NO;
}
- (BOOL) isEqualToString:(NSString *)string
{
if (self == string)
return YES;
else
return [self compare:string options:NSLiteralSearch range:NSMakeRange(0, [self length])] == NSOrderedSame;
}
@end

mayoff commented Dec 4, 2012

If you know how to create an NSString instance whose class is actually NSString please let me know.

+[NSString allocWithZone:] returns an instance of NSPlaceholderString. You can use class_createInstance to create an instance of NSString, but all of the initializers except init will throw an exception. If you use init, most other messages (e.g. length) will raise an exception.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment