jonprasetyo
jonprasetyo

Reputation: 3586

NSMutableDictionary and NSCopying, want to add an object into the key

I am very new to Objective-C and I have come across the NSMutableDictionary. I want to insert an object into the key and from my understanding, you need to make a copy by using the NSCopying class.

I have been reading the Apple's Documentations and I am still puzzled with this. Also I have been searching for examples and I can only seem to find ones that have keys as NSString objects which seems to be automatically copied.

Here is the part of my implementation code:

@implementation League
- (void) setPlayerInTeam: (Club*) theClub playerObject: (Person*) person{
    [playerTeam setObject:theClub forKey: person];
}
@end

the forKey:person is obviously wrong, how do I make a copy of this by using the NSCopying? Sorry for being a newbie but I am eager to learn.

Many thanks.

Upvotes: 0

Views: 705

Answers (2)

JeremyP
JeremyP

Reputation: 86651

The keys you use in an NSMutableDictionary have certain restrictions. NSMutableDictionary copies the key when you use -setObject:forKey:. This means the key must support the NSCopying protocol. So Person needs to be declared like this:

@interface Person : PersonsSuperClass <NSCopying>

and it needs to implement the method -copyWithZone: If the Person class is immutable and you are using ARC, -copyWithZone: can simply return self.

-(id) copyWithZone: (NSZone*) zone
{
    return self;  // or return [self retain] if not using ARC.
}

If Person is not immutable, -copyWithZone: needs to make a new Person object that is exactly the same as the one you are copying.

-(id) copyWithZone: (NSZone*) zone
{
    Person* theCopy = [[[self class] allocWithZone: zone] init];
    // copy all the data from self to theCopy
    return theCopy;
}

There are some other things you need to be careful of too. The method -isEqual: must be semantically correct because that is how comparisons are done by NSMutableDictionary. For example, if a Person is uniquely indexed by a property called userId, you need to make -isEqual: use that property to determine if two Person object are equal. A similar rule exists for -hash, two objects that compare equal using -isEqual: must have the same hash.

Upvotes: 1

Jeffery Thomas
Jeffery Thomas

Reputation: 42588

As Hot Licks said, you must create a -[Person copyWithZone:] method.

@interface Person : NSObject <NSCopying>
@property NSString *firstName;
@property NSString *lastName;
…
@end

@implementation
- (id)copyWithZone:(NSZone *)zone
{
    Person *copy = [[[self class] allocWithZone:zone] init];
    if (copy) {
        copy->_firstName = [self.firstName copyWithZone:zone];
        copy->_lastName = [self.lastName copyWithZone:zone];
        …
    }
    return copy;
}
@end

It's a real pain and full of possible subtle defects. In addition, I would highly recommend creating -[Person isEqual:] and -[Person hash] methods to avoid other types of defects.

Sometimes it's a must, but avoid it when possible.

Upvotes: 0

Related Questions