0

I have a UITabelView displaying a list of items(returned from the server), users will be able to select any item and add it to his own section. Upon selecting an item, I am retrieving the selected item details and saving it to a pList file, the list will then be displaying a small icon informing the user that the item is added to his section. User will be able to remove it from his section by tapping the icon again.

To know if the item is already in his section, i am using

[self.myItemsArray containsObject:item]

Everything is working perfect if the user don't exit the application. The issue is occurring once the app is restarted. When I retrieve the tableview list from the database or from server, all the items will not be shown as on my list and [self.myItemsArray containsObject:item] will return NO for the previous added items.

I was searching for an alternative way, by creating an NSArray of my items id's and will then check if the new array will contains the item id to display the icon. the new issue is that the id is returned as double from the server and stored as it is. The application is crashing when creating the array:

[self.myItemsArray valueForKey:@"Id"]

myItemsArray is an array of items(item is an NSDictionary containing all the details)

So i am desperate now,could anyone help me by resolving any of the above issues? I prefer the first one, since containsObject will be more simple, but I don't mind to solve it with the second choice if the first will not work.

Iphone User
  • 1,930
  • 2
  • 17
  • 26
  • are you saving the plist file to the file system whenever you add an item? And, on app start, are you re-reading the plist file and rebuilding `self.myItemsArray` with its contents? – fullofsquirrels May 12 '16 at 19:32
  • @fullofsquirrels exactly, when retrieving the list from server, i am saving the plist file to the document folder. On app start, i'm reading the plist file and rebuilding myItemsArray with its content, display it in the UITableView then make a hit to refresh the content from server..Even without the new hit server, containsObject is returning NO – Iphone User May 12 '16 at 19:35
  • Are the items that you're putting into the plist custom objects that you've created? And if so, what does your `-isEqual:` method look like? For `containsObject:` to work, especially if you're persisting/unpersisting objects, you have to have a reproducible means of determining whether two objects are "the same" – fullofsquirrels May 12 '16 at 19:38
  • @fullofsquirrels yes they are custom objects, i am saving them as [NSKeyedArchiver archivedDataWithRootObject:MyObjectsArray] then to retrieve them as NSArray i am using [[NSKeyedUnarchiver unarchiveObjectWithData:data] mutableCopy]. To compare, I am only using the native containsObject: to check if the retrieved array contains a specific object – Iphone User May 12 '16 at 19:43
  • @fullofsquirrels should i implement my own -isEqual:? and if so where should i implement it? Each item contains the key "Id" with type double value which i can use it to compare if the object is identical – Iphone User May 12 '16 at 19:58
  • the `containsObject:` method on NSArray takes the item that you pass and evaluates each object in the array for equality using the object class' `isEqual:` method, so you'd want to implement `isEqual:` on your custom object class. You can do a quick experiment by comparing that id alone, and if that works and solves your problem, I can make a formal answer with some additional info about some good/best practices for constructing a reasonably generic `isEqual:` method. – fullofsquirrels May 12 '16 at 20:40
  • @fullofsquirrels, thank you for leading me to the correct way:)) .. I was able to solve it by using this tutorial (http://nshipster.com/equality/) .. I did override isEqual: method in my object class with the following: - (BOOL)isEqual:(id)object { objectItem* itemToCompare = object; if(self.internalBaseClassIdentifier == itemToCompare.internalBaseClassIdentifier) return YES; else return NO; } .. I think this should be enough in case i am not mistaken. Thank you again for your time to make me understand the difference between equality and identity – Iphone User May 12 '16 at 20:41
  • @fullofsquirrels sure you can make it as formal answer, and i would appreciate the additional info for good practices. I would glady make it as the answer:) – Iphone User May 12 '16 at 20:51

1 Answers1

1

You'll need to make sure you have a good isEqual: method defined for your custom class, since that's what NSArray uses to determine containment: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/#//apple_ref/occ/instm/NSArray/containsObject:

Let's say this class has something like a 'key' or 'id' value that is unique for each instance of the class (which in your case is a double type). This will not always be the case, of course; it's often an aggregate of individual properties/ivars that constitutes a unique 'key', but for the purposes of this discussion let's say that such a field exists. Your code might look something like this (all in the .m):

static double const EPSILON = .000000001; // You'll need to be the judge of how "close" values can be to each other but still be distinct

@interface MyObjectClass: NSObject
@property (nonatomic, readonly) double uniqueKey;
@end

@implementation MyObjectClass

// ...

- (BOOL)isEqual:(id)object
{
    if (self == object) { return YES; }
    if (!object isKindOfClass:[MyObjectClass class]]) { return NO; }

    MyObjectClass *myObject = (MyObjectClass *)object;
    if (abs(self.uniqueKey - myObject.uniqueKey) < EPSILON) { return YES; }
    return NO;
}

//...

@end

Note that you should NOT check for direct equality between two float or double values; see How dangerous is it to compare floating point values? for a good discussion about the pitfalls of working with floating point and double precision values.

Community
  • 1
  • 1
fullofsquirrels
  • 1,828
  • 11
  • 16