1

Im quite new in objective-c and im trying to do a UItableview app. The whole concept is that i have two views, both tableviews. In the first view controller I have months and depending on which month you are pressing Im changing an integer (int currentMonth) in the second view controller. In the second view controller I want to present a table view with animals. The animals should only show if they are "huntable" and also present how long they are "huntable" and Ive written code for that and it works.

The problem is that with my current code Im deleting objects out of the animalArray and reloading the data for the tableview in cellForRowAtIndexPath and that makes scrolling really slow.

Ive tried to come up with other solutions but so far no luck so I hope someone could push me in the right direction.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{


static NSString *CellIdentifier = @"DjurCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
//skapar en variabel av Appdelegate för att komma åt arrayen med djur.
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];


UIImage *background = [self cellBackgroundForRowAtIndexPath:indexPath];

UIImageView *cellBackgroundView = [[UIImageView alloc] initWithImage:background];
cellBackgroundView.image = background;
cell.backgroundView = cellBackgroundView;

if (cell== nil) {
    cell = [[UITableViewCell alloc]
            initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];}

//Skapar en label och länkar den med storyboard.
UILabel *animalNameLabel = (UILabel *)[cell viewWithTag:104];

UILabel *animalDetailLabel = (UILabel *)[cell viewWithTag:102];
NSString *strmonth;



switch (self.currentMonth) {

    case 0:
        strmonth=@"Juli";
        break;
    case 1:
        strmonth=@"Augusti";
        break;
    case 2:
        strmonth=@"September";
        break;
    case 3:
        strmonth=@"Oktober";
        break;
    case 4:
        strmonth=@"November";
        break;
    case 5:
        strmonth=@"December";
        break;
    case 6:
        strmonth=@"Januari";
        break;
    case 7:
        strmonth=@"Februari";
        break;
    case 8:
        strmonth=@"Mars";
        break;
    case 9:
        strmonth=@"April";
        break;
    case 10:
        strmonth=@"Maj";
        break;
    case 11:
        strmonth=@"Juni";
        break;
    case 12:
        strmonth=@"Juli";
        break;

    default:
        break;
}
        //Algoritm för utskrivandet av hur lång tid en art är jaktbar. Om nuvarande månad är större än jaktstarten och mindre än jaktstoppet.
        if ((self.currentMonth>[[appDelegate.animalArray objectAtIndex:indexPath.row]getjaktstartmonth])&&(self.currentMonth<[[appDelegate.animalArray objectAtIndex:indexPath.row]getjaktstopmonth])) {
             animalNameLabel.text = [[appDelegate.animalArray objectAtIndex:indexPath.row]getArt];
            animalDetailLabel.text = @"Jaktbar hela månaden";
        }
        //Om nuvarande månad är lika med jaktstarten.
        else if(self.currentMonth==[[appDelegate.animalArray objectAtIndex:indexPath.row]getjaktstartmonth]){
             animalNameLabel.text = [[appDelegate.animalArray objectAtIndex:indexPath.row]getArt];
            animalDetailLabel.text = [NSString stringWithFormat:@"Jaktbar från och med den %i:e %@",[[appDelegate.animalArray objectAtIndex:indexPath.row]getjaktstartday],strmonth];
        }
        //Om nuvarande månad är lika med jaktstoppet.
        else if(self.currentMonth==[[appDelegate.animalArray objectAtIndex:indexPath.row]getjaktstopmonth]){
             animalNameLabel.text = [[appDelegate.animalArray objectAtIndex:indexPath.row]getArt];
            animalDetailLabel.text = [NSString stringWithFormat:@"Jaktbar till och med den %i:e %@",[[appDelegate.animalArray objectAtIndex:indexPath.row]getjaktstopday],strmonth];
        }
        //I övriga fall
        else{
            animalNameLabel.text = [[appDelegate.animalArray objectAtIndex:indexPath.row]getArt];
            animalDetailLabel.text = [NSString stringWithFormat:@"Ej Jaktbar"];


        }

//This is what makes the scrolling slow.

        if ([animalDetailLabel.text isEqual:@"Ej Jaktbar"]) {
            [appDelegate.animalArray removeObjectAtIndex:indexPath.row];
            [tableView reloadData];
        }


return cell;

}

Any ideas how I should change the code?

2 Answers 2

2

NEVER call reload data from within cellForRowAtIndexPath. What is the purpose of that?

I do not think is is a good idea to delete a field from that array that "drives" the content of the table. You could do that without reloading data but you will have to expect that the table requests for a cell for which you don't have a corresponding index in your array.

However, you are far better off when you change the data in some more appropriate method (viewDidLoad?). You may force the table to relaoad its data from any method that is not invoked by the reloading process. All datasource methods are invoked due to the reload.

If your code was slightly different then you would risk an infinite loop here. In your case its not infinte, because you just delete all ocurrences of "Ej Jaktbar" from your array, which is finite. But for each ocurrence you reload the table again and again. cellForRorAtIndexPath will be called again and again starting with cell 0. But your table did not have a chance of releasing unused cells. I guess that you are even waisting lot of memory for cell views taht you never actually use.

3
  • I agree, calling reloadData from within cellForRowAtIndexPath: could result in x amount of reloads before the actual data is presented. Which would slow down the presentation of content alot. Commented Jun 26, 2013 at 12:47
  • Thank you for you answer. I tried to do my changes in the array in the viewDidLoad method but it did not work. My month identifier currentMonth from the didSelectRowAtIndexpath method in my first view is not changing in the viewDidLoad. Not in the viewWillAppear method either. If I put my code in viewDidAppear it works but the whole list shows a short while before it loads. Any particular thing Ive missed? I guess I should be using the viewWillAppear method?
    – dingo_
    Commented Jun 26, 2013 at 20:22
  • Where do you get that data for the list from? Why do you manipulate it afterwards and before acutally displaying the table. Commented Jun 27, 2013 at 7:30
0

You could use this approach:

DISCLAIMER - This is pseudo-thinktank right through, it's also written without and form of IDE. So there's risk it wont work or compile at all.

Within viewDidLoad() of your animalTableViewController you could do the following:

-(void)viewDidLoad
{

   AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];

   // it would be nice to get the month here. You could probably get it from a custom init of the viewController.
   [appDelegate removeNonHuntableAnimalsFromDatasourceWithMonth:self.Month];

   // the rest of your code

}

The function within your AppDelegate could look a little like this:

As seen from your case it's dependant on which month it is, so you'd probably need to get the current month here. Which can be sent from viewDidLoad in your animalViewController

-(void)removeNonHuntableAnimalsFromDatasourceWithMonth:(NSString *)month
{
    // iterate through all animals 
    for (animalObject *animal in self.animalArray) 
    {
        // if the month is lesser than the start or greater than the stop.
        // calling  [property intValue] can be done if the properties are of the type NSString
        if ([month intValue] < [animal.jaktStart intValue] || [month.intValue] > [animal.jaktStopp intValue])
        {
            // remove the animal from the datasource
            [self.animalArray removeObject:animal];
        }

    }
}

If the structure were to look something like the following:

animalArray[0] = [AnimalObject]
                 (jaktStart) = 5
                 (jaktStopp) = 6
                 (art) = Duck
animalArray[1] = [AnimalObject]
                 (jaktStart) = 1
                 (jaktStopp) = 8
                 (art) = Moose
animalArray[2] = [AnimalObject]
                 (jaktStart) = 11
                 (jaktStopp) = 12
                 (art) = Wolf
animalArray[3] = [AnimalObject]
                 (jaktStart) = 2
                 (jaktStopp) = 4
                 (art) = Polarbear

So if your datasource were to look like the above structure the loop would with month 11 modify the structure to the following.

animalArray[0] = [AnimalObject]
                 (jaktStart) = 11
                 (jaktStopp) = 12
                 (art) = Wolf

DISCLAIMER This code might or might not work at all! Hope it gave you some ideas.

1
  • Thank you @Da_smokes .. I took a week off and jumped right back into it.. Problems solved.. I found the problem in the first viewcontroller. I didn't set currentMonth before the pushViewController call.. slapping my hand against my forehead
    – dingo_
    Commented Jul 4, 2013 at 14:13

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.