为什么以及如何在objective-c中使用someArray[5]?

为什么以及如何在objective-c中使用someArray[5]?,objective-c,Objective C,我认为新的符号是这样工作的: someArray[5]变成了 someArray[5]实际上将变成[someArray objectAtIndexedSubscript:5] 然而,在NSArray.h和NSOrderedSet.h中,我看到: - (id)objectAtIndexedSubscript:(NSUInteger)idx NS_AVAILABLE(10_8, 6_0); 因此,objectAtIndexedSubscript仅适用于IOS6 我尝试编写以下简单代码: NSArr

我认为新的符号是这样工作的:

someArray[5]变成了

someArray[5]实际上将变成[someArray objectAtIndexedSubscript:5]

然而,在NSArray.h和NSOrderedSet.h中,我看到:

- (id)objectAtIndexedSubscript:(NSUInteger)idx NS_AVAILABLE(10_8, 6_0);
因此,objectAtIndexedSubscript仅适用于IOS6

我尝试编写以下简单代码:

NSArray * someArray =@[@"hello",@"World",@"World"];
NSOrderedSet * someOS = [NSOrderedSet orderedSetWithArray:someArray];
PO(someArray);
PO(someOS);
PO(someArray[0]);
PO(someOS[0]); //Exception thrown here
代码在某些位置中断[0]

-[__NSOrderedSetI objectAtIndexedSubscript:]: unrecognized selector sent to instance 0x8b1fac0
在NSArray和NSOrderedSet中,都有一个文本NS_可用(10_8,6_0)

但它并没有在NSArray上中断,而是在Deredset上中断。为什么?


额外的好处:我如何使它也适用于OnOrderSet和category(需要检查它是否尚未定义)

更深入地研究这一点,它看起来在iOS 6中只有-objectAtIndexedSubscript:但在iOS 5和iOS 6中NSArray都有-objectAtIndexedSubscript:

我的测试显示了以下几点

- (void)testNSOrderedSetObjectAtIndexedSubscript
{
    NSString *systemVersion = [UIDevice currentDevice].systemVersion;
    NSString *message = @"NSOrderedSet for %@ does not respond to -objectAtIndexedSubscript:";

    NSOrderedSet *orderedSet = [NSOrderedSet orderedSet];
    STAssertTrue([orderedSet respondsToSelector:@selector(objectAtIndexedSubscript:)], message, systemVersion);
}

- (void)testNSArrayObjectAtIndexedSubscript
{
    NSString *systemVersion = [UIDevice currentDevice].systemVersion;
    NSString *message = @"NSArray for %@ does not respond to -objectAtIndexedSubscript:";

    NSArray *array = [NSArray array];
    STAssertTrue([array respondsToSelector:@selector(objectAtIndexedSubscript:)], message, systemVersion);
}
iOS 5.0模拟器

Test Case '-[SIObjectTests testNSArrayObjectAtIndexedSubscript]' started.
Test Case '-[SIObjectTests testNSArrayObjectAtIndexedSubscript]' passed (0.000 seconds).
Test Case '-[SIObjectTests testNSOrderedSetObjectAtIndexedSubscript]' started.
/Users/jthomas/workspaces/si-catalog-order-ios/SICatalogOrderTests/SIObjectTests.m:20: error: -[SIObjectTests testNSOrderedSetObjectAtIndexedSubscript] : "[orderedSet respondsToSelector:@selector(objectAtIndexedSubscript:)]" should be true. NSOrderedSet for 5.0 does not respond to -objectAtIndexedSubscript:
Test Case '-[SIObjectTests testNSOrderedSetObjectAtIndexedSubscript]' failed (0.000 seconds).
Test Case '-[SIObjectTests testNSArrayObjectAtIndexedSubscript]' started.
Test Case '-[SIObjectTests testNSArrayObjectAtIndexedSubscript]' passed (0.000 seconds).
Test Case '-[SIObjectTests testNSOrderedSetObjectAtIndexedSubscript]' started.
Test Case '-[SIObjectTests testNSOrderedSetObjectAtIndexedSubscript]' passed (0.000 seconds).
iOS 6.0模拟器

Test Case '-[SIObjectTests testNSArrayObjectAtIndexedSubscript]' started.
Test Case '-[SIObjectTests testNSArrayObjectAtIndexedSubscript]' passed (0.000 seconds).
Test Case '-[SIObjectTests testNSOrderedSetObjectAtIndexedSubscript]' started.
/Users/jthomas/workspaces/si-catalog-order-ios/SICatalogOrderTests/SIObjectTests.m:20: error: -[SIObjectTests testNSOrderedSetObjectAtIndexedSubscript] : "[orderedSet respondsToSelector:@selector(objectAtIndexedSubscript:)]" should be true. NSOrderedSet for 5.0 does not respond to -objectAtIndexedSubscript:
Test Case '-[SIObjectTests testNSOrderedSetObjectAtIndexedSubscript]' failed (0.000 seconds).
Test Case '-[SIObjectTests testNSArrayObjectAtIndexedSubscript]' started.
Test Case '-[SIObjectTests testNSArrayObjectAtIndexedSubscript]' passed (0.000 seconds).
Test Case '-[SIObjectTests testNSOrderedSetObjectAtIndexedSubscript]' started.
Test Case '-[SIObjectTests testNSOrderedSetObjectAtIndexedSubscript]' passed (0.000 seconds).

我有一个更好的答案

对于不支持
-objectAtIndexedSubscript:
的iOS版本,此代码将动态修补
SensoredSet

#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);
    }
}
#导入
#进口
id PatchedObjectatinIndexedSubscript(id self、SEL cmd、nsu整数索引)
{
返回[自对象索引:索引];
}
void PatchedSetObjectAtIndexedSubscript(id self_u、SEL cmd_u、id object、整数索引)
{
返回[self_u-replaceObjectAtIndex:index with object:object];
}
void sipatchSensorDeredSet()
{
字符类型[6];
如果(!class_getInstanceMethod([SensorDeredSet类],@selector(objectAtIndexedSubscript:)){
sprintf(类型,@@:%s,@encode(整数));
类\u addMethod([SensorDeredSet类],
@选择器(objectAtIndexedSubscript:),
(IMP)修补对象索引下标,
类型);
}
如果(!class_getInstanceMethod([NSMutableOrderedSet类],@selector(setObject:atIndexedSubscript:)){
sprintf(类型,“v:@%s”,“编码(整数));
类\添加方法([NSMutableOrderedSet类],
@选择器(setObject:atIndexedSubscript:),
(IMP)PatchedSetObjectAtIndexedSubscript,
类型);
}
}

在应用程序开始时(
-application:didfishlaunchingwithoptions:
可能)调用
sipatchSensorDeredSet()

Jeffry answer非常棒,并提供有关声明选择器工作方式的见解

作为替代方案,我只需这样做:

self.businessDetailed.Phones.array[0];
然后我会告诉我未来的孙子们把它改成

self.businessDetailed.Phones[0];
当iphone15上市时


与Jeffry的解决方案相比,工作量要少得多,但同时边际成本会略微增加。

您的PO()是什么?我没有得到任何例外。什么是Statsert true,它与其他函数有什么区别?@JimThio
Statsert*
函数是OCUnit的一部分。为什么不直接使用普通的NSAssert呢?因为代码是为数不多的用户编写的。是追踪类似问题的好方法。哇。哇。所以我们不能只做普通的分类,对吗?v:@%s为什么不v:@s?为什么在s之前有%s?此处未列出@JimThio这不是一个普通类别,因为我不想覆盖iOS 6中的实际实现,所以当方法不可用时,我会有条件地覆盖它。@JimThio文档中没有列出NSUInteger的编码,所以我使用
@encode(NSUInteger)
动态获取编码<代码>%s是
sprintf
插入实际编码的方式。谢谢。这真是太棒了。