1.0----7添加对象的下标来支持你的类

添加对象的下标来支持你的类
传统上,集合,如数组和字典访问对象时,程序员不得不访问的方法数组或字典来获取或设置该对象上。举例来说,这是创建一个可变的字典里,增加了两个键和值将它和检索这些值回传统的方式:

NSString *const kFirstNameKey = @"firstName"; NSString *const kLastNameKey = @"lastName";
    NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];

[dictionary setValue:@"Tim" forKey:kFirstNameKey];
    [dictionary setValue:@"Cook" forKey:kLastNameKey];
    __unused NSString *firstName = [dictionary valueForKey:kFirstNameKey];
    __unused NSString *lastName = [dictionary valueForKey:kLastNameKey];

但随着LLVM编译器的所有进步,这些代码现在可以缩短到这一点:

NSString *const kFirstNameKey = @"firstName"; NSString *const kLastNameKey = @"lastName";
    NSDictionary *dictionary = @{
                                 kFirstNameKey : @"Tim",
                                 kLastNameKey : @"Cook",
                                 };
    __unused NSString *firstName = dictionary[kFirstNameKey];
    __unused NSString *lastName = dictionary[kLastNameKey];

从NSString *到NSString *const的区别在于,NSString *值的指针可以改变指向(虽然不能改变内容,但是对于系统常量来说还是非常危险啊,这应该算是设计缺陷了,所以MacOS 10.6修改过来了),NSString *const的就是无论内容,指向都不能改了。类似于C++中const *及 const * const的区别。

你可以看到,我们通过提供关键的大括号初始化字典。同样的事情阵列。下面是我们如何用传统的创建和使用数组:

 NSArray *array = [[NSArray alloc] initWithObjects:@"Tim", @"Cook", nil];
    __unused NSString *firstItem = [array objectAtIndex:0];
    __unused NSString *secondObject = [array objectAtIndex:1];

现在用对象下标,我们可以缩短这个代码,如下所示: 

NSArray *array = @[@"Tim", @"Cook"];
    __unused NSString *firstItem = array[0];
    __unused NSString *secondObject = array[0];

LVM甚至没有就此打住。您可以添加下标,以自己的类。有两种类型的下标中:
按键下标
有了这个,你可以将该值设置为一个对象内部的特定按键,就像你在字典中。您也可以访问/读取从物体内部的值通过提供关键。
通过索引下标
与数组,可以通过索引 设置/获取,对象内的值。这是有道理的,类似于数组的类所在的要素在于,可以通过索引来表示一种自然秩序。
对于第一个例子中,我们将通过关键要看下标。要做到这一点,我们将创建一个名为人用将firstname和lastname类。然后,我们将允许程序员通过简单地提供所述键的那些属性,以改变第一和最后一个名称。

您可能希望通过键给类添加下标的原因是像这种情况,如果你的属性名称是挥发性的,你想允许程序员设置这些值,而无需担心是否这些属性的名称将在以后更改;否则,编程是最好是使用直接属性。实施下标的另一个原因是,如果你想隐藏具体的实施或者从程序员那里声明属性,而不是直接获取他们。

为了在自己的类支持下标者皆,你必须实现你的类中的以下两个方法,把方法签名放到类的头文件;否则,编译器将不知道你的类支持此下标。

祥见  C/C++中extern关键字详解

#import <Foundation/Foundation.h>
    /* We will use these as the keys to our firstName and lastName
     properties so that if our firstName and lastName properties' names
     change in the future in the implementation, we won't break anything
     and our class will still work, as we can simply change the value of
     these constants inside our implementation file我们将使用这些作为密钥对我们的名字和姓氏 
     性,因此,如果我们的名字和姓氏属性的名称 
     改变未来的执行,我们不会破坏任何东西 
     和我们的类仍然可以工作,因为我们可以简单地改变内部的值而不破坏整体性*
*/

extern NSString *const kFirstNameKey; extern NSString *const kLastNameKey; @interface Person : NSObject @property (nonatomic, copy) NSString *firstName; @property (nonatomic, copy) NSString *lastName; - (id) objectForKeyedSubscript:(id<NSCopying>)paramKey; - (void) setObject:(id)paramObject forKeyedSubscript:(id<NSCopying>)paramKey; @end

该objectForKeyedSubscript:方法会被调用的类,每当程序员提供了一个键,想读你的类中key的值。提供给您的参数显然是从哪个程序员想要读取的key值。为了配合这种方法,setObject方法:forKeyedSubscript:方法在你的类中会被调用,每当程序员想要设置的值给指定的键。因此,在我们的实现中,我们要检查给定的键是否是名字和姓氏的键,如果是,我们将设置/获取我们类的姓和名的值:

 #import "Person.h"
NSString *const kFirstNameKey = @"firstName"; NSString *const kLastNameKey = @"lastName";
@implementation Person
- (id) objectForKeyedSubscript:(id<NSCopying>)paramKey{
NSObject<NSCopying> *keyAsObject = (NSObject<NSCopying> *)paramKey; if ([keyAsObject isKindOfClass:[NSString class]]){ NSString *keyAsString = (NSString *)keyAsObject; if ([keyAsString isEqualToString:kFirstNameKey] ||
                [keyAsString isEqualToString:kLastNameKey]){
return [self valueForKey:keyAsString]; }
}
return nil; }
- (void) setObject:(id)paramObject forKeyedSubscript:(id<NSCopying>)paramKey{ NSObject<NSCopying> *keyAsObject = (NSObject<NSCopying> *)paramKey;
if ([keyAsObject isKindOfClass:[NSString class]]){
NSString *keyAsString = (NSString *)keyAsObject; if ([keyAsString isEqualToString:kFirstNameKey] ||
                [keyAsString isEqualToString:kLastNameKey]){
                [self setValue:paramObject forKey:keyAsString];
            }
} }
@end

因此,在这段代码中,在objectForKeyedSubscript:方法中,我们给出了一个key,我们预计将返回在我们与该键实例相关联的对象。这个键给我们的是一个对象,它符合NSCopying协议。换句话说,它是一个对象,我们可以做出的一个副本,如果我们想。如果这个键是一个一个字符串,这样我们可以把它与我们在我们类之前预定义的键值进行比较,如果匹配,我们将在我们的类中设置属性值。然后,我们将使用一个名为NSObject的valueForKey 方法:返回给定的键关联的值。但很明显,在这样做之前,我们保证给定的关键是,我们预期的键之一。在的setObject:forKeyedSubscript:我们的方法做的正好相反。我们设定键的值,而不是返回他们设置的值。

现在,在你的应用程序在其他地方,你可以实例化Person类型的对象,并使用kFirstNameKey和kLastNameKey预定义的键更改名字的价值和lastName属性,如下所示:

  Person *person = [Person new];
    person[kFirstNameKey] = @"Tim";
    person[kLastNameKey] = @"Cook";
    __unused NSString *firstName = person[kFirstNameKey];
    __unused NSString *lastName = person[kLastNameKey];
This code will achieve exactly the same effect as the more direct approach of setting the properties of a class:
    Person *person = [Person new];
    person.firstName = @"Tim";
    person.lastName = @"Cook";
__unused NSString *firstName = person.firstName;
    __unused NSString *lastName = person.lastName;

您还可以通过索引支持下标,以同样的方式做阵列。这是非常有用的,如前面提到的,允许程序员访问有一个类内部的自然顺序的对象。但也有不除数组许多数据结构的地方是有意义的秩序和多种元素,通过不同的关键,它适用于多种数据结构的下标。于是我将使用通过索引来说明下标这个例子有点做作。在前面的例子中,我们有一流的人用的姓氏和名字。现在,如果你想要让程序员能够通过提供的0和姓氏索引读取头名提供1指数中,所有你所要做的就是声明objectAtIndexedSubscript:与方法setObject:atIndexedSubscript:在方法你的类的头文件,然后写的落实。下面是我们如何申报Person类的头文件,这些方法:

 -(id) objectAtIndexedSubscript:(NSUInteger)paramIndex;
- (void) setObject:(id)paramObject atIndexedSubscript:(NSUInteger)paramIndex;

实施也很简单。我们以指数和作用于它在某种程度上是有道理的我们类。我们决定第一次命名为具有0和索引1,索引因此,如果我们得到的0索引,用于设置一个值,我们的第一个名称的值设置为传入对象的姓氏,并因此于:

- (id) objectAtIndexedSubscript:(NSUInteger)paramIndex{
switch (paramIndex){ case 0:{
return self.firstName;
break; }
case 1:{
return self.lastName; break;
} default:{
                [NSException raise:@"Invalid index" format:nil];
            }
}
return nil; }
- (void) setObject:(id)paramObject atIndexedSubscript:(NSUInteger)paramIndex{ switch (paramIndex){
case 0:{
self.firstName = paramObject; break;
}
case 1:{
                self.lastName = paramObject;
22 |
Chapter 1: Implementing Controllers and Views
break; }
            default:{
                [NSException raise:@"Invalid index" format:nil];
} }
}
Now we can test out what we’ve written so far, like so:
    Person *person = [Person new];
    person[kFirstNameKey] = @"Tim";
    person[kLastNameKey] = @"Cook";
    NSString *firstNameByKey = person[kFirstNameKey];
    NSString *lastNameByKey = person[kLastNameKey];
    NSString *firstNameByIndex = person[0];
    NSString *lastNameByIndex = person[1];
if ([firstNameByKey isEqualToString:firstNameByIndex] && [lastNameByKey isEqualToString:lastNameByIndex]){ NSLog(@"Success");
}else{
NSLog(@"Something is not right");
}

如果你已经按照这个配方中的所有步骤,你应该看到成功的价值,现在打印到控制台。

 
posted @ 2014-10-19 17:09  尐苹果  阅读(466)  评论(0编辑  收藏  举报