2

I have a list of Objects that I pull from a web service. When I update my UITableView, I retrieve the objects again from the web service, and compare them to each other for equality. I then remove the ones that are not present, and insert the new objects, then update my UITableView. How can I test to see if the new object equals the old object? I've created a test for clarity..

requestA should equal requestC, but fails.

Is this possible to do without looking at each property value as the objects have many values?

I was originally comparing the ID only, but this doesn't work as sometimes other property values change and the ID stays the same.

    Request *requestA = [[Request alloc] init];
    Request *requestB = [[Request alloc] init];
    Request *requestC = [[Request alloc] init];

    requestA.requestID = @"1";
    requestA.productName = @"Clutch";
    requestB.requestID = @"2";
    requestB.productName = @"Wiper";
    requestC.requestID = @"1";
    requestC.productName = @"Clutch";

    if (requestA == requestB)
        NSLog(@"A == B");

    if (requestA == requestC)
        NSLog(@"A == C");

    if ([requestA isEqual:requestB])
        NSLog(@"A isEqual B");

    if ([requestA isEqual:requestC])
        NSLog(@"A isEqual C");

    // Look at the pointers:
    NSLog(@"%p", requestA);
    NSLog(@"%p", requestB);
    NSLog(@"%p", requestC);
vinylDeveloper
  • 687
  • 2
  • 7
  • 25

4 Answers4

6

Check this answer: How do I compare objects in Objective-C?

You need to implement -isEqual: and -hash methods for your Request class.

Community
  • 1
  • 1
Salavat Khanov
  • 4,100
  • 2
  • 15
  • 27
  • Thank you. This was very helpful, I accepted @wcd, just because it gave me some examples, but this is the implementation I used. – vinylDeveloper Jan 16 '15 at 15:53
6

isEqual: is a method declared in NSObject Protocol. From official docs of isEqual:

This method defines what it means for instances to be equal. For example, a container object might define two containers as equal if their corresponding objects all respond YES to an isEqual: request. See the NSData, NSDictionary, NSArray, and NSString class specifications for examples of the use of this method.

If two objects are equal, they must have the same hash value. This last point is particularly important if you define isEqual: in a subclass and intend to put instances of that subclass into a collection. Make sure you also define hash in your subclass.

Thus, as Salavat Khanov pointed out in his answer:

You need to implement -isEqual: and -hash methods for your Request class.

You want to do something like this:

// TestRequest.h
@interface TestRequest : NSObject

@property (nonatomic) NSString *requestID;
@property (nonatomic) NSString *productName;

@end

// TestRequest.m
#import "TestRequest.h"

@implementation TestRequest
- (BOOL)isEqual:(TestRequest *)object {
    if (self == object) {
        return YES;
    }

    if (![self.requestID isEqual:object.requestID]) {
        return NO;
    }

    if (![self.productName isEqual:object.productName]) {
        return NO;
    }

    return YES;
}

- (NSUInteger)hash {
    // this is a very simple hash function
    return [self.requestID hash] ^ [self.productName hash];
}
@end

or you can use a custom method:

- (BOOL)isEqualToRequest:(TestRequest *)otherRequest {
    return [self.requestID isEqualToString:otherRequest.requestID] && 
           [self.productName isEqualToString:otherRequest.productName];
}
wcd
  • 1,144
  • 8
  • 15
1

You need to overwrite isEqual: of your Request object to specify the properties to compare. Write sth. like this:

- (BOOL)isEqual:(id)other {
    if (other == self) return YES;
    if (!other || ![other isKindOfClass:[self class]]) return NO;
    if (![(id)[self name] isEqual:[other name]]) return NO;
    // add other checks if needed
    return YES;
}
clash
  • 532
  • 4
  • 17
  • 2
    You neglected to mention that you must also implement `hash`. ALWAYS implement both methods together. – rmaddy Jan 16 '15 at 15:17
0

First off. == is a check for "are these two objects actually the SAME OBJECT". I.e. They are just two pointers to the same but of memory.

You need to be using the isEqual method. However, in order to do this properly you need to override the method in the class.

Something like...

- (BOOL)isEqual:(Request *)otherObject
{
    return [self.productName isEqual:otherObject.productName]
    && [self.requestID isEqual:otherObject.requestID];
}
Fogmeister
  • 76,236
  • 42
  • 207
  • 306
  • You neglected to mention that you must also implement `hash`. ALWAYS implement both methods together. – rmaddy Jan 16 '15 at 15:18