Objective-C如何自己实现一个基于数组下标的属性访问模式
在iOS6.0以及OS X10.8之后,Apple引入了一套非正式协议(informal protocol)与Objective-C语法直接绑定。当你实现了这其中的方法之后即可使用数组下标来访问属性元素。
在Foundation库中,NSArray类实现了- (id)objectAtIndexedSubscript:(NSUInteger)idx方法。因此,我们可以这么来访问数组元素:
NSArray *arr = @[@100, @200, @300]; NSNumber *num = arr[0];
上述arr[0]就相当于[arr objectAtIndex:0]。
而NSMutableArray在基于NSArray的基础上又实现了- (void)setObject:(id)anObject atIndexedSubscript:(NSUInteger)index方法。这样我们可以通过数组下标来读写相应元素,比如:
NSMutableArray *arr = [NSMutableArray arrayWithArray:@[@100, @200, @300]]; arr[2] = arr[0];
而NSDictionary类实现了- (id)objectForKeyedSubscript:(id)key方法。这样我们能以数组下标的形式来访问相应键的值。比如:
NSDictionary *dict = @{@"key" : @"value"}; NSString *value = dict[@"key"];
而NSMutableDictionary在NSDictionary类的基础上又实现了- (void)setObject:(id)object forKeyedSubscript:(id < NSCopying >)aKey方法。这样,我们能以数组下标的方式来读写相应键的值。比如:
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:@{@"key":"@Hello"}]; dict[dict[@"key"]] = @"world";
下面我们通过实现这四个方法,自己实现一个能同时使用这四种下标方式访问模式的类。
// // main.m // objCTest // // Created by Zenny Chen on 12-2-7. // Copyright (c) 2014年 Neon Media Studio. All rights reserved. // #import <Foundation/Foundation.h> @interface MyContainer : NSObject { @private NSMutableDictionary *mDict; NSMutableArray *mArray; } - (void)setObject:(id)object forKeyedSubscript:(id < NSCopying >)aKey; - (id)objectForKeyedSubscript:(id)key; - (void)setObject:(id)anObject atIndexedSubscript:(NSUInteger)index; - (id)objectAtIndexedSubscript:(NSUInteger)idx; @end @implementation MyContainer - (instancetype)init { self = [super init]; mDict = [[NSMutableDictionary alloc] initWithDictionary:@{@"key1":@"value1", @"key2":@"value2"}]; mArray = [[NSMutableArray alloc] initWithArray:@[@100, @200, @300, @400]]; return self; } - (void)dealloc { if(mDict != nil) { [mDict removeAllObjects]; [mDict release]; mDict = nil; } if(mArray != nil) { [mArray removeAllObjects]; [mArray release]; mArray = nil; } [super dealloc]; } - (void)setObject:(id)object forKeyedSubscript:(id < NSCopying >)aKey { [mDict setObject:object forKey:aKey]; } - (id)objectForKeyedSubscript:(id)key { return [mDict objectForKey:key]; } - (void)setObject:(id)anObject atIndexedSubscript:(NSUInteger)index { const NSUInteger length = [mArray count]; if(index > length) return; if(index == length) [mArray addObject:anObject]; else [mArray replaceObjectAtIndex:index withObject:anObject]; } - (id)objectAtIndexedSubscript:(NSUInteger)idx { if(idx >= [mArray count]) return nil; return [mArray objectAtIndex:idx]; } @end int main (int argc, const char * argv[]) { @autoreleasepool { // insert code here... MyContainer *cont = [[MyContainer alloc] init]; cont[@"mykey"] = @"myvalye"; NSLog(@"key1 is: %@", cont[@"key1"]); NSLog(@"key2 is: %@", cont[@"key2"]); NSLog(@"mykey is: %@", cont[@"mykey"]); cont[4] = @500; cont[2] = @-300; NSLog(@"The value[4] = %@", cont[4]); NSLog(@"The value[3] = %@", cont[3]); NSLog(@"The value[2] = %@", cont[2]); } return 0; }