Objective-C 实现自己的 Subscripting Methods 下标方法

在前一篇 Xcode 4.4/4.5 新特性 / LLVM 4.0 新语法 提到了 Xcode 4.4 之后对数组和字典的操作可以用下面的方式:


id value = array[i];
array[i] = newObj;
id value = dictionary[@"key"];
dictionary[@"key"] = newObj;

上面几行语句实际调用的方法分别对应如下:

NSArray : - (id)objectAtIndexedSubscript: (NSUInteger)index;
NSMutableArray : - (void)setObject: (id)obj atIndexedSubscript: (NSUInteger)index;
NSDictionary : - (id)objectForKeyedSubscript: (id <NSCopying>)key;
NSMutableDictionary : - (void)setObject: (id)anObject forKeyedSubscript: (id <NSCopying>)aKey;

所以,如果你希望自己定义的类可以支持 obj[i] 和 obj[@"key"] 的方式来读取和设置值的话,就可以实现上面相应的方法,只是要处理好你自己参数和结果类型。现在就来看看下面自定义类 TestClass 的实现和执行效果:

TestClass.h
 1//
 2//  TestClass.h
 3//  NewXcodeTest
 4//
 5//  Created by Unmi on 1/22/13.
 6//  Copyright (c) 2013 Unmi. All rights reserved.
 7//
 8
 9#import <Foundation/Foundation.h>
10
11@interface TestClass : NSObject
12- (id) objectAtIndexedSubscript: (NSUInteger)index;
13- (void) setObject: (id)obj atIndexedSubscript: (NSUInteger)index;
14- (id) objectForKeyedSubscript: (id <NSCopying>)key;
15- (void) setObject: (id)anObject forKeyedSubscript: (id <NSCopying>)aKey;
16@end

必须在头文件中声明需要用到的读写方法,否则 test[i] 这样用时无法通过编译。

TestClass.m
 1//
 2//  TestClass.m
 3//  NewXcodeTest
 4//
 5//  Created by Unmi on 1/22/13.
 6//  Copyright (c) 2013 Unmi. All rights reserved.
 7//
 8
 9#import "TestClass.h"
10
11@implementation TestClass
12
13- (id) objectAtIndexedSubscript: (NSUInteger)index {
14    NSLog(@"get value by index: %d", index);
15    return @"Unmi";
16}
17- (void) setObject: (id)obj atIndexedSubscript: (NSUInteger)index{
18    NSLog(@"set value %@, atIndex: %d", obj, index);
19}
20
21- (id) objectForKeyedSubscript: (id <NSCopying>)key {
22    NSLog(@"get value by key: %@", key);
23    return @"http://unmi.cc";
24}
25
26- (void) setObject: (id)anObject forKeyedSubscript: (id <NSCopying>)aKey {
27    NSLog(@"set value %@ for key: %@", anObject, aKey);
28}
29
30@end

使用 TestClass 的代码:
1TestClass* test = [[TestClass alloc] init];
2id value = test[100];
3test[1] = @200;    
4value = test[@"Name"];
5test[@"Blog"] = @"http://unmi.cc";

上面的代码执行效果如下,控制台输出:

2013-01-26 14:30:00.342 NewXcodeTest[955:c07] get value by index: 100
2013-01-26 14:30:00.344 NewXcodeTest[955:c07] set value 200, atIndex: 1
2013-01-26 14:30:00.346 NewXcodeTest[955:c07] get value by key: Name
2013-01-26 14:30:00.348 NewXcodeTest[955:c07] set value http://unmi.cc for key: Blog

对应一下,果真如此。

实际应用中,你可以在 TestClass 中声明些实例变量,比如数组,字典类型的变量,让以上的四个 Subscripting Methods 下标方法去访问这些实例变量中的值,这样从代码和语义上省去了些麻烦。比如 TestClass 中声明了一个字典实例变量 options 和数组变量 items,我们就无需写成:

test.options[@"name"],而可简单的写成 test[@"name"],test.items[i] 变成  test[i], 就是这么回事。

参考:1. Objective-C的新特性
            2. WWDC2012:Objective-C的新特性 永久链接 https://yanbin.blog/objective-c-implement-subscripting-methods/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。