0

I have an NSMutableOrdered set that holds two types of objects (that I created), Pieces and Others.

Piece and Other both have their isEqual method overridden like so:

Piece:

- (BOOL)isEqual:(Piece *)object
{
    if (([title isEqualToString:[object title]])
        && ([composer isEqualToString:[object composer]])
        && (major == [object major])
        && (tempo == [object tempo])
        && (pieceKey == [object pieceKey])
        && (pieceTime == [object pieceTime]))
        return YES;
    else 
        return NO;
}

Other:

- (BOOL)isEqual:(Other *)object
{
    if (([title isEqualToString:[object title]])
        && ([subTitle isEqualToString:[object subTitle]])
        && ([description isEqualToString:[object description]])
        && (otherTime == [object otherTime]))
        return YES;
    else 
        return NO;
}  

I also override the hash of both classes to create a unique hash for each instance (by getting the int value of the ivars and adding them).

In my app, An Other is removed from the set, then when I try to add a piece to the set, I get this:

-[Other isEqual:]: message sent to deallocated instance 0x80d5680

here is the hash method:

- (NSUInteger)hash
{
    NSUInteger prime = 31;
    NSUInteger result = 1;
    result = prime * (result + [title intValue]);
    result = prime * (result + [composer intValue]);
    result = prime * (result + major);
    result = prime * (result + tempo);
    result = prime * (result + pieceKey);
    result = prime * (result + pieceTime);
    return result;
}

If anybody knows why this is happening, I would really some help.

Thanks,

Kyle Rosenbluth
  • 1,672
  • 4
  • 22
  • 38
  • Are you intending to call [object description]? Description is an NSObject function. – Matt Melton Apr 26 '12 at 15:22
  • That could be the problem, I have an instance variable called description, I completely forgot about NSObject's description method – Kyle Rosenbluth Apr 26 '12 at 15:24
  • I just double checked that, and the instance that I remove with [pieceSession removeObjectAtIndex:section - 2]; is the same instance that is getting the isEqual method. – Kyle Rosenbluth Apr 26 '12 at 15:32
  • I'm sorry, I somehow misread your post. I thought you were using an NSMutableSet. What is an NSMutableOrdered set? I can't find this in the docs. – Kristian Duske Apr 26 '12 at 15:42

2 Answers2

2

This is not really an answer, but it will help us to find the problem. Some questions:

  • Are you sure that 0x80d5680 is the instance that was previously removed?
  • How do you remove it from the set?
  • Do you modify the state of your objects after adding them?
  • Are you sure that your hashes are unique (sum of int value of ivars sound sounds suspicious).

Finally, make sure that your objects obey this rule:

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.

See NSObject Protocol Reference for more information.

Kristian Duske
  • 1,769
  • 9
  • 14
  • Thanks Kristian, Here are some answers. I am sure that 0x80d5680 is the instance previously removed. I remove it with the removeObjectAtIndex method. I can modify the state of my objects after adding them, but in this specific case I do not. I modified my original post to include my hash method for pieces. – Kyle Rosenbluth Apr 26 '12 at 15:47
  • Your isEqual methods do not override NSObject's isEqual, which takes a single parameter of type id. Your implementations actually overload that method. Don't know whether that's intentional or not, but the result is that an instance of Piece is never equal to an instance of Other. Also, concerning your hash method, are you aware that, if a string does not begin with a number (disregarding leading whitespace), intValue will return 0? – Kristian Duske Apr 26 '12 at 16:01
  • 1
    I suppose that NSMutableOrderedSet uses an NSMutableSet internally to determine duplicates plus an NSMutableArray to keep an order. If you add an object to such a data structure and then modify its state in such a way that the hash value changes, the following will happen on removal: It will find the object in the internal array by its index, but it won't find it in the set because the hash has changed. Since the object was retained by the ordered set, and it was found in the array, it is released, but it remains in the set, causing the exception when the next object is inserted. – Kristian Duske Apr 26 '12 at 16:10
  • To sum up: Make sure that your hash values are stable. Putting objects with unstable hash values into a hashing data structure is a very bad idea. – Kristian Duske Apr 26 '12 at 16:12
  • Thanks Kristian, what do you suggest I use to make my hashes stable? – Kyle Rosenbluth Apr 26 '12 at 16:14
  • If your hashes depend on part of the state of your object, you shouldn't modify that part of the state after adding it to a hashing data structure. The curious thing is though that you wrote earlier that you don't modify the state after insertion, so there maybe something else going on here, too. Oh, and you should probably use the hashes of the string instance variables instead of intValue. – Kristian Duske Apr 26 '12 at 16:20
0

I believe isEqual is called on members as part of the set comparison, as a set is a group of unique items. Perhaps you should add the member to the new set before removing from the old one?

Hope this helps!

Matt Melton
  • 2,493
  • 19
  • 25
  • 1
    Why would isEqual be called on the removed instance of Other when Piece is added? Also, NSSet is unordered, but isEqual is used to determine whether the added object is a duplicate. – Kristian Duske Apr 26 '12 at 15:30
  • Sorry, I misread the post and thought Kyle was using an NSMutableSet. – Kristian Duske Apr 26 '12 at 15:43