Reputation: 33050
I made this simple code:
PO(self.last10000Places);
PO(PlaceMark);
NSMutableArray *placemarks= [NSMutableArray arrayWithArray:PlaceMark];
PO(placemarks);//Breakpoint1
[placemarks removeObjectsInArray:self.last10000Places];
PO(placemarks);//Breakpoint2
[self.last10000Places addObjectsFromArray:placemarks];
Here PO is simply my macro
#define CLog( s, ... ) NSLog( @"<%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#define PO(x) CLog(@#x ": %@", x)
#define PD(x) CLog(@#x ": %f", x)
Now, I am aware that nsmutablearray need to have isEqual implemented.
So I put this code:
@interface CLLocation (equal)
- (BOOL)isEqual:(CLLocation*)other;
@end
@implementation CLLocation (equal)
- (BOOL)isEqual:(CLLocation*)other {
if ([self distanceFromLocation:other] ==0)
{
return true;
}
return false;
}
@end
@interface CLPlacemark (equal)
- (BOOL)isEqual:(CLPlacemark*)other;
@end
@implementation CLPlacemark (equal)
- (BOOL)isEqual:(CLPlacemark*)other {
PO(self);
PO(other);
if (![self.name isEqual:other.name])
{
return false;
}
if (![self.location isEqual:other.location ])
{
return false; //NEVER called
}
return true;//breakpoint3 but strange result
}
@end
Then I step through the code. Now this is what's strange.
at breakpoint1 I saw:
2012-09-22 21:40:53.959 GetAllDistricts[18381:c07] <0x74a7480 SDViewController.m:(82)> placemarks: (
"Ross Sea, Ross Sea @ <-77.43947520,-168.68218520> +/- 100.00m, region (identifier <-75.73637772,-0.00216940> radius 2140218.36) <-75.73637772,-0.00216940> radius 2140218.36m"
at breakpoint3 I saw:
2012-09-22 21:41:22.964 GetAllDistricts[18381:c07] <0xd77fab0 SDViewController.m:(37)> self: Alexander Island, Antarctica @ <-71.05224390,-70.87965290> +/- 100.00m, region (identifier <-70.73927686,-71.91489801> radius 258243.49) <-70.73927686,-71.91489801> radius 258243.49m
2012-09-22 21:41:22.964 GetAllDistricts[18381:c07] <0xd77fab0 SDViewController.m:(38)> other: South Atlantic Ocean, South Atlantic Ocean, Antarctica @ <-42.60533670,-21.93128480> +/- 100.00m, region (identifier <-41.51023865,-31.60774370> radius 4958095.65) <-41.51023865,-31.60774370> radius 4958095.65m
2012-09-22 21:41:22.965 GetAllDistricts[18381:c07] <0xd787390 SDViewController.m:(37)> self: South Atlantic Ocean, South Atlantic Ocean, Antarctica @ <-42.60533670,-21.93128480> +/- 100.00m, region (identifier <-41.51023865,-31.60774370> radius 4958095.65) <-41.51023865,-31.60774370> radius 4958095.65m
2012-09-22 21:41:22.965 GetAllDistricts[18381:c07] <0xd787390 SDViewController.m:(38)> other: South Atlantic Ocean, South Atlantic Ocean, Antarctica @ <-42.60533670,-21.93128480> +/- 100.00m, region (identifier <-41.51023865,-31.60774370> radius 4958095.65) <-41.51023865,-31.60774370> radius 4958095.65m
It's obvious that placemarks contains Ross Sea. So what the hell removeObjectsinArray
call isEqual
with South Atlantic Ocean?
Also the Ross Sea is not removed from placemarks by breakpoint2.
I implemented isEqual I do not implement hash
Is this the problem?
Upvotes: 0
Views: 324
Reputation: 33050
I have figured out what the problem is. Implementing -(NSUInteger) hash somehow fix the problem.
The documentation says that we have to override hash when we override isEqual
Looks like removeObjects use the hash for optimization and figure out that the hash is unequal and conclude that isEqual will return false without checking.
So I simply add this code:
@interface CLLocation (equal)
- (BOOL)isEqual:(CLLocation*)other;
@end
@implementation CLLocation (equal)
- (BOOL)isEqual:(CLLocation*)other {
if ([self distanceFromLocation:other] ==0)
{
return true;
}
return false;
}
- (NSUInteger) hash
{
NSUInteger theHash = (NSUInteger) (self.coordinate.latitude *360 + self.coordinate.longitude);
CLog(@"thehash %d",theHash);
return theHash;
}
@end
@interface CLPlacemark (equal)
- (BOOL)isEqual:(CLPlacemark*)other;
@end
@implementation CLPlacemark (equal)
- (BOOL)isEqual:(CLPlacemark*)other {
PO(self);
PO(other);
if (![self.name isEqual:other.name])
{
return false;
}
if (![self.location isEqual:other.location ])
{
return false;
}
return true;
}
-(NSUInteger) hash
{
return self.name.hash;
}
Upvotes: 2
Reputation: 32054
Your question could use some tidying up, and perhaps a condensed explanation of the current behavior, and how it deviates from the expected.
But, I'm wondering if (based on the title of your question) you're confused about the fact that the arrayWithArray:
method actually creates and maintains a separate collection. Your objects are not copied, but in this scenario:
NSArray *objects = [NSArray arrayWithObjects:@"A", @"B", @"C", nil];
NSMutableArray *mute = [NSMutableArray arrayWithArray:objects];
NSArray *removals = [NSArray arrayWithObjects:@"A", @"C", nil];
[mute removeObjectsInArray:removals];
Your end result will be:
objects = { @"A", @"B", @"C" }
mute = { @"B" }
Does this example help clarify anything?
Upvotes: 1