kursus
kursus

Reputation: 1404

UITableView timer based display cell

I have an array of products meant to be displayed in a tableView (dynamic cells) :

{"Products" :
[
    {
        "NAME": "MyProduct1",
        "TIMELINE": 4
    },
    {
        "NAME": "MyProduct2",
        "TIMELINE": 10
    },
    {
        "NAME": "MyProduct3",
        "TIMELINE": 18
    },
...
]}

The TIMELINE property is supposed to define the number of seconds after which the cell is displayed.

The starting point for the timeline is defined elsewhere and not always equal to 0. It can be for example 12, in this case :

My cells are filled with :

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

    MyResults* media = [MyResults getInstance];
    [media productDetails:indexPath.row];

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"results" forIndexPath:indexPath];
    UILabel *nameLabel = (UILabel *)[cell viewWithTag:666];
    nameLabel.text = media.productName;
    cell.clipsToBounds = YES;
    return cell;
}

MyResults.m :

_products = [json objectForKey:@"Products"];

-(void)productDetails:(NSUInteger)row {
    NSDictionary* details = [_products objectAtIndex:row];
    _productName= [details objectForKey:@"NAME"];
}

From my research I have found two approaches, but can't get them to work :

Method 1 : insertrowsatindexpaths

I would like to filter the main array so it only keeps TIMELINE > STARTINGPOINT products.

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(%@ > %@)", timelineValue, startingPoint];

I'm having a hard time retrieving timelineValue, since my products array is parsed with cellForRowAtIndexPath in the first place.

Method 2 : heightforrowatindexpath

The array is fully loaded in tableView, height is set to 0 and set back to normal when the TIMELINE time is reached. I can set it to 0 but can't figure how to set a NSTimer to give it original height.

I'm not sure if any of this is a good solution, especially with memory management matters. Any thoughts appreciated.

Bonus : the cell display have to be animated

Upvotes: 1

Views: 339

Answers (1)

Asaf
Asaf

Reputation: 2168

Assuming you have a view controller with an UITableView, you'll also need to retain a local timeStart variable and two arrays - one for the products, and one for the products which we already added to the table view:

 @interface ViewController () <UITableViewDataSource, UITableViewDelegate>

 @property (weak, nonatomic) IBOutlet UITableView *tableView;
 @property (nonatomic, strong) NSArray *products;
 @property (nonatomic, strong) NSMutableArray *dataSource;
 @property (nonatomic) NSInteger timelineStart;

 @end

Your viewDidLoad should look like that:

 - (void)viewDidLoad
 {
     [super viewDidLoad];

     self.dataSource = [NSMutableArray array];

     self.timelineStart = 0; // TODO: CHANGE IT TO WHAT YOU NEED
     self.products = [NSArray arrayWithObjects:@{@"NAME" : @"MyProduct1", @"TIMELINE" : @(4)}, @{@"NAME" : @"MyProduct2", @"TIMELINE" : @(10)}, @{@"NAME" : @"MyProduct3", @"TIMELINE" : @(18)},nil];
     // Change the products parsing to whatever you need

     for (NSInteger i = 0; i < self.products.count; i++) {
         NSDictionary *obj = [self.products objectAtIndex:i];
         if ([[obj objectForKey:@"TIMELINE"] integerValue] > self.timelineStart) {
             NSInteger timeInterval = [[obj objectForKey:@"TIMELINE"] integerValue] - self.timelineStart;
             [NSTimer scheduledTimerWithTimeInterval:timeInterval target:self selector:@selector(addNewProductToTableView:) userInfo:obj repeats:NO];
       }
   }
}

- (void)addNewProductToTableView:(NSTimer *)timer
{
     NSDictionary *obj = [timer userInfo];

     dispatch_async(dispatch_get_main_queue(), ^{

         NSMutableArray *indexPaths = [NSMutableArray array];
         NSInteger currentCount = self.dataSource.count;
         [indexPaths addObject:[NSIndexPath indexPathForRow:0 inSection:0]];

         [self.dataSource insertObject:obj atIndex:0];

         // tell the table view to update (at all of the inserted index paths)
         [self.tableView beginUpdates];
         [self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationTop];
         [self.tableView endUpdates];

    });
}

And finally the must have tableview delegate.

 #pragma mark - UITableViewDataSource

 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
 {
     return 1;
 }

 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
 {
     return [self.dataSource count];
 }

 #pragma mark - UITableViewDelegate

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyIdentifier"];
     if (cell == nil) {
         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MyIdentifier"];
     }

     NSDictionary *item = [self.dataSource objectAtIndex:indexPath.row];
     cell.textLabel.text = [item objectForKey:@"NAME"];

     return cell;
}

Hope this answer your demands (it also includes the animation).

Upvotes: 2

Related Questions