I am aware of how normal NSArray
concatenation works in Objective-C. This is not that question.
I have data that is being incrementally updated from a web service. My object has the following class definition (with a lot removed):
// NoteTemplate.h
#import <UIKit/UIKit.h>
@interface NoteTemplate
@property (copy, nonatomic) NSString *objectId;
I am caching a list of these on-device and checking at launch to see if there are any new or updated NoteTemplate
objects in my database to load. So, I end up with two arrays:
NSArray <NoteTemplate *> *oldArray
NSArray <NoteTemplate *> *newArray
If there are no updates, then all I need to do is simply concatenate the two arrays together and that's that.
If there are updates, however, I want to combine the two arrays, but whenever there is a common objectId
, the item in newArray
should take precedence over the item in oldArray
.
Thus far, I am brute-forcing it like this:
- (void)updateNoteTemplatesWithArray:(NSArray *)newTemplates {
NSArray *oldTemplates = [self getNoteTemplates];
NSMutableArray *combined = [NSMutableArray arrayWithArray:newTemplates];
for (NoteTemplate *noteTemplate in oldTemplates) {
NSArray *matches = [combined filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id blockTemplate, NSDictionary<NSString *,id> *bindings) {
return [((NoteTemplate *)blockTemplate).objectId isEqualToString:noteTemplate.objectId];
}]];
if (matches.count == 0) {
[combined addObject:noteTemplate];
}
}
[self setNoteTemplates:[combined copy]];
}
Is there a more optimized way to do this? I can't see that this will affect performance at all, so perhaps an optimization is unnecessary. Still, this approach feels hacky and way over-engineered.
To extend @Larme's suggestion with Set usage you can try the following approach:
@interface NoteTemplate: NSObject
@property (copy, nonatomic) NSString *objectId;
@property (copy, nonatomic) NSString *text;
- (instancetype)initWithObjectId:(NSString *)objectId text:(NSString *)text;
@end
@implementation NoteTemplate
- (instancetype)initWithObjectId:(NSString *)objectId text:(NSString *)text {
self = [super init];
if (self != nil) {
_objectId = objectId;
_text = text;
}
return self;
}
- (BOOL)isEqual:(id)object {
return [self.objectId isEqualToString:[object objectId]];
}
@end
And the usage code:
NoteTemplate *nt1 = [[NoteTemplate alloc] initWithObjectId:@"1" text:@"old set"];
NoteTemplate *nt2 = [[NoteTemplate alloc] initWithObjectId:@"2" text:@"old set"];
NoteTemplate *nt3 = [[NoteTemplate alloc] initWithObjectId:@"1" text:@"new set"];
NoteTemplate *nt4 = [[NoteTemplate alloc] initWithObjectId:@"3" text:@"new set"];
NSSet <NoteTemplate *> *oldSet = [NSSet setWithObjects:nt1, nt2, nil];
NSSet <NoteTemplate *> *newSet = [NSSet setWithObjects:nt3, nt4, nil];
NSMutableSet <NoteTemplate *> *mergedSet = [newSet mutableCopy];
[mergedSet unionSet:oldSet];
for (NoteTemplate *note in mergedSet) {
NSLog(@"Set item %@ %@", note.objectId, note.text);
}
After executing this code you'll see in the log:
Set item 3 new set
Set item 1 new set
Set item 2 old set
I assume that's what you were looking for.