Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why and how someArray[5] works in objective-c?

Tags:

objective-c

I thought the new notation works like this:

someArray[5] turns into

someArray[5] will actually turn into [someArray objectAtIndexedSubscript:5]

However, in NSArray.h and NSOrderedSet.h I saw this:

- (id)objectAtIndexedSubscript:(NSUInteger)idx NS_AVAILABLE(10_8, 6_0);

So, objectAtIndexedSubscript is only available for IOS6.

I experimented making this simple code:

NSArray * someArray =@[@"hello",@"World",@"World"];
NSOrderedSet * someOS = [NSOrderedSet orderedSetWithArray:someArray];
PO(someArray);
PO(someOS);
PO(someArray[0]);
PO(someOS[0]); //Exception thrown here

The code break at someOS[0]

-[__NSOrderedSetI objectAtIndexedSubscript:]: unrecognized selector sent to instance 0x8b1fac0

in BOTH NSArray and NSOrderedSet, there is a text NS_AVAILABLE(10_8, 6_0);

Yet it doesn't break on NSArray yet break on NSOrderedSet. Why?

Bonus: How do I make it work for NSOrderedSet too with category (need to check that it's not already defined)

like image 588
user4951 Avatar asked Nov 30 '25 02:11

user4951


1 Answers

I have a better answer!

This code will dynamically patch NSOrderedSet for versions of iOS that don't support -objectAtIndexedSubscript:.

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

id PatchedObjectAtIndexedSubscript(id self_, SEL cmd_, NSUInteger index)
{
    return [self_ objectAtIndex:index];
}

void PatchedSetObjectAtIndexedSubscript(id self_, SEL cmd_, id object, NSUInteger index)
{
    return [self_ replaceObjectAtIndex:index withObject:object];
}

void SIPatchNSOrderedSet()
{
    char types[6];

    if (!class_getInstanceMethod([NSOrderedSet class], @selector(objectAtIndexedSubscript:))) {
        sprintf(types, "@@:%s", @encode(NSUInteger));
        class_addMethod([NSOrderedSet class],
                        @selector(objectAtIndexedSubscript:),
                        (IMP)PatchedObjectAtIndexedSubscript,
                        types);
    }

    if (!class_getInstanceMethod([NSMutableOrderedSet class], @selector(setObject:atIndexedSubscript:))) {
        sprintf(types, "v@:@%s", @encode(NSUInteger));
        class_addMethod([NSMutableOrderedSet class],
                        @selector(setObject:atIndexedSubscript:),
                        (IMP)PatchedSetObjectAtIndexedSubscript,
                        types);
    }
}

At the start of your application (-application:didFinishLaunchingWithOptions: maybe) call SIPatchNSOrderedSet().

like image 136
Jeffery Thomas Avatar answered Dec 02 '25 20:12

Jeffery Thomas



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!