0
  1. My app crash ramdomly in _storeArray.
  2. In viewDidLoad, have a method [self loadUrl] that parse a xml file then add an dictionary [_storeArray addObject:dictionary];
  3. The crash happens when somehow the carousel reusingView call first then [self loadUrl].
  4. I have added the if(_storeArray) but it still crash.

This is the exception:

2013-04-06 09:33:35.254 Semhora[7347:907] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'

This is the code:

- (void)loadURL:(NSString *)newURL{

    // Create a success block to be called when the asyn request completes
    TBXMLSuccessBlock successBlock = ^(TBXML *tbxmlDocument) {


        [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
        // If TBXML found a root node, process element and iterate all children
        if (tbxmlDocument.rootXMLElement)
        {
            // Obtain root element
            TBXMLElement * root = tbxml.rootXMLElement;
            if (root)
            {
                [_storeArray removeAllObjects];
                TBXMLElement * elem_PLANT = [TBXML childElementNamed:@"principal" parentElement:root];
                while (elem_PLANT !=nil)
                {
                    TBXMLElement * elem_title = [TBXML childElementNamed:@"title" parentElement:elem_PLANT];
                    NSString *titleName = [TBXML textForElement:elem_title];

//                    TBXMLElement * elem_artist = [TBXML childElementNamed:@"text" parentElement:elem_PLANT];
//                    NSString *artistName = [TBXML textForElement:elem_artist];

                    TBXMLElement * elem_thumb = [TBXML childElementNamed:@"thumb_url" parentElement:elem_PLANT];
                    NSString *thumbName = [TBXML textForElement:elem_thumb];

                    TBXMLElement * elem_photo1 = [TBXML childElementNamed:@"photo1" parentElement:elem_PLANT];
                    NSString *photo1Name = [TBXML textForElement:elem_photo1];

                    TBXMLElement * elem_photo2 = [TBXML childElementNamed:@"photo2" parentElement:elem_PLANT];
                    NSString *photo2Name = [TBXML textForElement:elem_photo2];

                    TBXMLElement * elem_photo3 = [TBXML childElementNamed:@"photo3" parentElement:elem_PLANT];
                    NSString *photo3Name = [TBXML textForElement:elem_photo3];

                    TBXMLElement * elem_photo4 = [TBXML childElementNamed:@"photo4" parentElement:elem_PLANT];
                    NSString *photo4Name = [TBXML textForElement:elem_photo4];

                    TBXMLElement * elem_photo5 = [TBXML childElementNamed:@"photo5" parentElement:elem_PLANT];
                    NSString *photo5Name = [TBXML textForElement:elem_photo5];

                    NSDictionary *dictionary = [[NSDictionary alloc]initWithObjects:@[titleName, thumbName, photo1Name, photo2Name, photo3Name, photo4Name, photo5Name] forKeys:@[@"title", @"thumb_url", @"photo1", @"photo2", @"photo3", @"photo4", @"photo5",]];
                    elem_PLANT = [TBXML nextSiblingNamed:@"principal" searchFromElement:elem_PLANT];
                    [_storeArray addObject:dictionary];
                   [self startLoading:dictionary];
                     [[NSOperationQueue mainQueue] addOperationWithBlock:^{ [_carousel reloadData]; }];
                }


            }

        }

    };

    // Create a failure block that gets called if something goes wrong
    TBXMLFailureBlock failureBlock = ^(TBXML *tbxmlDocument, NSError * error) {
        NSLog(@"Error! %@ %@", [error localizedDescription], [error userInfo]);
    };

    // Initialize TBXML with the URL of an XML doc. TBXML asynchronously loads and parses the file.
    tbxml = [[TBXML alloc] initWithURL:[NSURL URLWithString:newURL]
                               success:successBlock
                               failure:failureBlock];

}

- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view
{
    //create new view if no view is available for recycling
    if (view == nil)
    {
        FXImageView *imageView = [[FXImageView alloc] initWithFrame:CGRectMake(0, 0, 200.0f, 200.0f)];
        imageView.contentMode = UIViewContentModeScaleAspectFit;
        imageView.asynchronous = YES;
        imageView.reflectionScale = 0.5f;
        imageView.reflectionAlpha = 0.25f;
        imageView.reflectionGap = 10.0f;
        imageView.shadowOffset = CGSizeMake(0.0f, 2.0f);
        imageView.shadowBlur = 5.0f;
        imageView.cornerRadius = 10.0f;
        view = imageView;
    }

    //show placeholder
    ((FXImageView *)view).processedImage = [UIImage imageNamed:@"placeholder.png"];

    //set image

    NSLog(@"%@", _storeArray);
    if (_storeArray) {

        NSDictionary *tempdic = [_storeArray objectAtIndex:0];

        switch (index) {
            case 0:
                [(FXImageView *)view setImageWithContentsOfURL:[NSURL URLWithString:[tempdic objectForKey:@"photo1"]]];
                break;
            case 1:
                [(FXImageView *)view setImageWithContentsOfURL:[NSURL URLWithString:[tempdic objectForKey:@"photo2"]]];
                break;
            case 2:
                [(FXImageView *)view setImageWithContentsOfURL:[NSURL URLWithString:[tempdic objectForKey:@"photo3"]]];
                break;
            case 3:
               [(FXImageView *)view setImageWithContentsOfURL:[NSURL URLWithString:[tempdic objectForKey:@"photo4"]]];
                break;
            case 4:
                [(FXImageView *)view setImageWithContentsOfURL:[NSURL URLWithString:[tempdic objectForKey:@"photo5"]]];
                break;
            default:
                break;
        }
    }

    return view;
}
Marckaraujo
  • 7,422
  • 11
  • 59
  • 97
  • I just cant edit this code to show clearly... – Marckaraujo Apr 06 '13 at 12:48
  • Thanks @Kerni, Wich button do you press to clearly shows the code? – Marckaraujo Apr 06 '13 at 12:58
  • Just because _storeArray isn't nil doesn't mean it contains objects. Where are you adding objects into _storeArray? It's an empty array so objectAtIndex:0 doesn't exist. – Jai Govindani Apr 06 '13 at 12:59
  • `if (_storeArray)` tests whether the object exists. Your error message says it exists but is empty. You can check whether `[_storeArray count]` is greater than zero. – Phillip Mills Apr 06 '13 at 12:59
  • @JaiGovindani, I am adding objects into _storeArray inside [self loadUrl] method that parse a xml file then add a dictionary to _storeArray. – Marckaraujo Apr 06 '13 at 13:01
  • @PhillipMills you are correct, it nows dont crash, but it nows randomly loads or not the images inside carousel. – Marckaraujo Apr 06 '13 at 13:04
  • I'm willing to bet that "randomly" is the wrong word. :) However, there's not enough code in what you've posted to show how the logic might be wrong. Try putting `NSLog(@"%@", _storeArray);` where you add the dictionary to the array and compare to what you're already logging. – Phillip Mills Apr 06 '13 at 13:07
  • Regarding formatting: check the edited source. Moved into using numbers, so the `-` char in front of the method declaration doesn't confuse the system to be another bullet point – Kerni Apr 06 '13 at 13:08
  • The reason for not showing an image is, that somewhere in your code, where you fill `_storeArray` it actually doesn't get filled with any data. If you can find the cause of that problem, please create a new question, since these are distinct issues. – Kerni Apr 06 '13 at 13:11
  • It looks like you simply don't get any data in your XML code when nothing is shown. Debug that, add log messages for the XML string that gets returned, and if you can't find the cause, create a new question with more information about that but please do not further edit this one! – Kerni Apr 06 '13 at 13:14

2 Answers2

1
  1. The current check for _storeArray only checks if the variable exists, but not if there are actually any elements in there. But after the check you simply assume that there is 1 element in the array without checking before if that is true.

    So change this

    if (_storeArray) {
    

    to this:

    if (_storeArray && [_storeArray count] > 0) {
    
  2. In addition you are assuming that the dictionary will have a key for photo1 etc. But if not, the generated URL will be empty and as a consequence the view might also get a nil URL.

    I would change that as follows:

    NSDictionary *tempdic = [_storeArray objectAtIndex:0];
    NSString *tempObjKey = nil;
    
    switch (index) {
        case 0:
            tempObjKey = @"photo1";
            break;
        case 1:
            tempObjKey = @"photo2";
            break;
        case 2:
            tempObjKey = @"photo3";
            break;
        case 3:
            tempObjKey = @"photo4";
            break;
        case 4:
            tempObjKey = @"photo5";
            break;
        default:
            break;
    }
    
    if (tempObjKey && [tempdic objectForKey:tempObjKey])
        [(FXImageView *)view setImageWithContentsOfURL:[NSURL URLWithString:[tempdic objectForKey:tempObjKey]]];
    }
    
Kerni
  • 15,241
  • 5
  • 36
  • 57
0

I need to know one thing, does your parsing happen before all this and successfully returns a array(NSLog it) because the array seems to be the problem here. You cannot directly take out the first object, you gotta stay defensive so do something like this.

 if (_storeArray) {

    if(_storeArray.count >0) {

    NSDictionary *tempdic = [_storeArray objectAtIndex:0];

    switch (index) { // all ur stmts }
    }}
Satheesh
  • 10,998
  • 6
  • 50
  • 93
  • My XML parse calls in viewDidLoad [self loadUrl], when its done it add [_storeArray addObject:dictionary] but sometimes the carousel call the method before XML completes the action. – Marckaraujo Apr 06 '13 at 13:14