-3

My array is returning an incorrect number for an index of an object that I am looking for. My array.count tells me there are 248 objects in the array, but the index that is returned is 2147483647. I saw this post that is similar to mine issue. I used the equality testing that was proposed in this post, but fell short of figuring out why this was happening and how to fix it.

Here is my code: (Edited with solution)

-(void)getChamberPrimaryCategories
{
    NSString *docsDir;
    NSArray *dirPaths;

    chamberCategoryArray = [[NSMutableArray alloc] init];

    // Get the documents directory
    dirPaths = NSSearchPathForDirectoriesInDomains(
                                                   NSDocumentDirectory, NSUserDomainMask, YES);

    docsDir = dirPaths[0];

    // Build the path to the database file
    _databasePath = [[NSString alloc]
                     initWithString: [docsDir stringByAppendingPathComponent:
                                      @"the_app.db"]];

    NSLog(@"%@",_databasePath);

    NSFileManager *filemgr = [NSFileManager defaultManager];

    if ([filemgr fileExistsAtPath: _databasePath ] == NO)
    {
        const char *dbpath = [_databasePath UTF8String];

        if (sqlite3_open(dbpath, &_the_app_database) == SQLITE_OK)
        {
            //do nothing
        } else {
            NSLog(@"Failed to open database");
        }
    }

    const char *dbpath = [_databasePath UTF8String];
    sqlite3_stmt    *statement;

    if (sqlite3_open(dbpath, &_the_app_database) == SQLITE_OK)
    {

        NSString *querySQL;

        querySQL = @"SELECT DISTINCT CHAMBER_PRIMARY_CATEGORY FROM PLACES WHERE CHAMBER_PRIMARY_CATEGORY IS NOT '' AND CHAMBER_PRIMARY_CATEGORY IS NOT NULL ORDER BY CHAMBER_PRIMARY_CATEGORY ASC";


        const char *query_stmt = [querySQL UTF8String];

        if (sqlite3_prepare_v2(_the_app_database,
                               query_stmt, -1, &statement, NULL) == SQLITE_OK)
        {
            NSLog(@"Query the database now.");
            //            if (sqlite3_step(statement) != SQLITE_ROW) {
            //                NSLog(@"Not okay");
            //            }
            while (sqlite3_step(statement) == SQLITE_ROW) {

                NSLog(@"Getting Information:");

                placesChamber *chamberCategoryObject = [[placesChamber alloc]init];

                NSString *placesPrimaryChamberCategory = [[NSString alloc]
                                                          initWithUTF8String:
                                                          (const char *) sqlite3_column_text(
                                                                                             statement, 0)];
                chamberCategoryObject.primary_category = placesPrimaryChamberCategory;

                NSLog(@"%@",placesPrimaryChamberCategory);

                [chamberCategoryArray addObject:chamberCategoryObject];
            }//end while

        }//end if
        else
        {
            NSLog(@"There is nothing in this database!");
            NSLog(@"%s",sqlite3_errmsg(_the_kearney_app_database));
        }
        sqlite3_finalize(statement);
        sqlite3_close(_the_kearney_app_database);

        [chamberCategoryTableView reloadData];

        NSLog(@"content offset: %f",chamberCategoryTableView.contentOffset.y);
        if (chamberCategoryTableView.contentOffset.y == 0)
        {

            placesChamber *searchChamber = [[placesChamber alloc] init];
            searchChamber.primary_category = @"Women's Clothing";
            NSUInteger index = [chamberCategoryArray indexOfObject:searchChamber];
            if (index == NSNotFound) {
                // no such chamber category
                NSLog(@"no such thing found");
            } else {
                // Found it at index
                NSLog(@"found it!");
            }


        }//end if

    }//end if

}

Debugger Showing Object in Array

Here is my placesChamber.m: (Needed for solution)

#import "placesChamber.h"

@implementation placesChamber

@synthesize ID;
@synthesize name;
@synthesize type;
@synthesize category;
@synthesize latitude;
@synthesize longitude;
@synthesize primary_category;
@synthesize secondary_category;

- (BOOL)isEqual:(id)object
{
    if ( self == object ) {
        return YES;
    }

    if ( ![object isKindOfClass:[placesChamber class]] ) {
        return NO;
    }

    if ( ![primary_category isEqualToString:[object primary_category]] ) {
        return  NO;
    }

    return YES;
}

@end
5
  • 3
    That's the value for NSNotFound. That means your object isn't in the array. Commented Feb 20, 2014 at 22:36
  • just check if the index is !=NSNotFound then make what you want with it , else it is not found in your array. Commented Feb 20, 2014 at 22:36
  • BTW - your array contains instances of placesChamber objects but you are looking for an NSNumber object and an NSString literal. That will never work. Commented Feb 20, 2014 at 22:37
  • @rmaddy I understand that it is the value for NSNotFound, but why am I getting it? I changed the issue with the NSNumber back to what it is supposed to be. By the way thanks for looking at my problem. Commented Feb 20, 2014 at 22:53
  • BTW, the debugger variable view is quite unreliable. The only way to be sure of what a value is is to use NSLog or, in the console, use po. Commented Feb 20, 2014 at 23:51

2 Answers 2

1

As I stated in the comments, you have populated your chamberCategoryArray with instances of placesChamber objects.

But you then attempt to find the index of one of these objects not by passing in a placesChamber object but by passing in an NSString literal. That simply won't work.

You need to do something like this:

placesChamber *searchChamber = [[placesChamber alloc] init];
searchChamber.primary_category = @"Women's Clothing";
NSUInteger index = [chamberCategoryArray indexOfObject:searchChamber];
if (index == NSNotFound) {
    // no such chamber category
} else {
    // Found it at index
}

This code assumes you have implemented the isEqual: method on your placesChamber class that compares the primary_category property.

Side notes: It is standard convention that classnames begin with uppercase letters while method names and variables begin with lowercase. All should use camel case.

Given this your class should be PlacesChamber and the property should be primaryCategory.

Sign up to request clarification or add additional context in comments.

8 Comments

I added this: placesChamber *searchChamber = [[placesChamber alloc] init]; searchChamber.primary_category = @"Women's Clothing"; NSUInteger index = [chamberCategoryArray indexOfObject:searchChamber]; if (index == NSNotFound) { // no such chamber category NSLog(@"no such thing found"); } else { // Found it at index NSLog(@"found it!"); } I still returned NSNotFound.
Update your question with the implementation of the isEqual: method on your placesChamber class.
Updated My question. Hope that is what you were looking for.
Given that implementation of your isEqual: method it should work. To be safe, add the hash method: - (NSUInteger)hash { return [self.primary_category hash]; }.
Without the isEqual: method it will only find an object with the same address.
|
0

I found that you have used indexOfObject: in the following 3 lines of code:

//1.
NSIndexPath *scrollIndexPath = [NSIndexPath indexPathForItem:[chamberCategoryArray indexOfObject:[defaults objectForKey:@"chamber filter category"]] inSection:0];

//2.
NSLog(@"index number: %lu",(unsigned long)[chamberCategoryArray indexOfObject:@"Women's Clothing"]);

//3.
if(NSNotFound == [chamberCategoryArray indexOfObject:[NSNumber numberWithInteger:1]]) {
    NSLog(@"not found");
}

And you are populating your chamberCategoryArray in the following line which is populating the array with an object of type placesChamber:

[chamberCategoryArray addObject:chamberCategoryObject];

Now if you pass an indexOfObject: message to an NSArray (or its subclass), it iterates through the array sending each object of the array an isEqual: message for equality and if one found, it returns the index, otherwise returns NSNotFound (as you are getting). And this equality comparison is based on the calculated hash code for each contained object, that is, if one object in the array has the same hash code (calculated internally) as the object it is being compared to, those are treated as equal.

In your example code:

  • In 1. you are checking the hash codes of the objects of the array with the hash code of [defaults objectForKey:@"chamber filter category"] and I'm not sure what defaults made of.
  • In 2. you are checking the elements against a NSString. But the objects of the array are of type placesChamber and hash codes for two different types never match and you would always get NSNotFound as a result.
  • In 3. you are doing the same error, this time with a NSNumber instead of a NSString. So the above logic holds here also.

So it's very obvious you would get NSNotFound (2147483647) as a occasional result.

I believe you are trying to return the index of an object from the array(which is actually a placesChamber by type) that has a property matching your test criteria. For that purpose you might use indexOfObjectPassingTest: method that takes a block to write your comparison logic. Inside the block, you can write your own customized logic of matching an array item with your search criteria and the object index would be returned accordingly.

Update

This what you are actually looking for at the first place:

NSString* criteria = @"Women's Clothing";
int index = [chamberCategoryArray indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
        placesChamber* item = obj;
        *stop = [item.primary_category isEqualToString:criteria];
        return *stop;
 }];

Here I have demonstrated how to obtain the index based on primary_category property of placesChamber objects. The same method holds for other properties as well.

6 Comments

You are incorrect about how indexOfObject: works. You are correct when you say that isEqual: is called for each object. But that's all that is done. The hash has no play in this at all. The two objects are considered equal if the isEqual: method returns YES. That's it. So it all depends on the proper implementation of the isEqual: method for the objects involved. Since the OP has an array with one type of objects and is looking for a different kind of object, isEqual: will never return YES.
@rmaddy isEqual: is strictly related to hash if not overridden. Actually, if not overridden, the default implementation of isEqual: compares the hash codes of the two objects for equality, returned by hash method, by themselves. For details please go through the link
Yes, isEqual: and hash should always be written as a pair so they work together properly. And yes, the default of both is basically the object address. None of that is relevant. Your answer keeps stressing that the hash is checked. It is not. The isEqual: method is called. That's it. If it so happens that the default implementation of isEqual: calls hash, that is an irrelevant secondary point. In this case, the user has (or needs to) override isEqual: to compare the object's properties as needed. When done, hash will have no play at all in this code.
@rmaddy Again I would beg to differ.:( hash has nothing to do with object's address rather it depends on the content and internal hashing algo. To satisfy, please create two NSString, str1 and str2 and set the same value like @"Hello" to both of them. Now if you compare them with isEqual:, you would find that it returns YES though the objects have different address. As for my answer is concerned, I have just tried to clarify that how isEqual behaves internally. But you are somewhat correct that I might have been over-explanative. Thanks :)
As I said, the default (in NSObject) uses the object address. NSString overrides both hash and isEqual: to work as expected. No address is used for NSString. Your example with NSString isn't relevant. A better example would be to create two NSObject instances.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.