0

I have a tabbar controller with 2 tabs - A and B. Tab A is a regular UIViewController and tab B is a TableViewController. I am trying to post a NSNotification from tab A and receive the the same and display the data in the table in tab B.

I post the notification from Tab A as below:

//"itemAddedToCartDictionary" is the object that I am sending with notification

[[NSNotificationCenter defaultCenter] postNotificationName:@"ItemAddedToCart" object:nil userInfo:itemAddedToCartDictionary];

In my tab B(TableViewController), I am trying to receive the above notification update an NSMutableArray property. The property is declared as below:

Tab B - .h file:

@property (nonatomic,strong) NSMutableArray *cart;

Tab B - .m file:

//providing manual setter method for 'items' hence not using @synthesize
- (void)setCart:(NSMutableArray *)cart{
    _cart = cart;
    [self.tableView reloadData];
}

Now, I have placed the code for receiving the notification(in Tab B) in AwakeFromNib as below:

- (void)awakeFromNib{
  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(addCurrentItemToCartFromNotification:) name:@"ItemAddedToCart" object:nil];
 }

The code, calls the method "addCurrentItemToCartFromNotification" upon receipt of the notification which the updates my property:

 - (void)addCurrentItemToCartFromNotification:(NSNotification *)notification{

 NSDictionary *currentItem = [notification.userInfo objectForKey:@"CART_ITEM_INFORMATION"];

if (!self.cart){
    NSLog(@"self.cart == nil");
    self.cart = [[NSMutableArray alloc] init];
}else{
    NSLog(@"self.cart != nil");
}

[self.cart addObject:currentItem];


}

Now this is the problem that I am facing:

After I post the notification in Tab A, Tab B(TableViewController) does not show any data even though I have updated my property in the above methods form the received notification. My TableView datasource methods are as below:

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


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"itemInCart";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

NSDictionary *cartItem = [self.cart objectAtIndex:indexPath.row];
cell.textLabel.text = [cartItem objectForKey:@"ITEM_NAME"];

return cell;
}

So Basically, I am accessing the property of my TableViewController(that I am receiving and updating from a Notification) from the datasource methods and it is not returning data.

Could you please let me know where and what I am missing here.

Thanks, Mike

EDIT: Following response from @Joel, @martin, @mkirci

Adding reload data to my "addCurrentItemToCartFromNotification" (method being called upon receipt of notification) helped. I a now able to see the items received fomr the notification on my Tab B(TableViewController).

Now here's what is happening:

Whenever a notification is received, the NSMutableArray property is being returned as nil. Hence, every time a notification is received, the alloc init happens for the NSMutableArray property (on the addCurrentItemToCartFromNotification) - (instead of just the first time). Hence, instead of incrementing the array with objects received from the notification, the array is re created every time and only the object form the current notification is being added.

Could you please throw some light on this situation please. Appreciate all your responses.

Thanks, Mike

EDIT2

Updated code snipped for initwithnibname for suggestion from @Joel

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{
if (!self.cart){
    NSLog(@"self.cart == nil");
    self.cart = [[NSMutableArray alloc] init];
}else{
    NSLog(@"self.cart != nil");
}
return self;
}
Mike G
  • 751
  • 3
  • 12
  • 21

2 Answers2

1

You are not reloading the table after adding an item.

The table is reloading only after creating and setting the array, you also need to update when an item is added.

mkirci
  • 169
  • 5
  • ... or use `insertRowsAtIndexPaths`, that gives a nicer animation. – Martin R Feb 06 '13 at 18:23
  • @mkirci - Your suggestion solved my issue. However, I am now facing another issue that I have posed on my question as an EDIT. Would appreciate if you could take a look at it and share your inputs. Thanks! – Mike G Feb 06 '13 at 18:44
  • @MikeG The code you posted should work, maybe you are assigning a nil value elsewhere that you do not expect to be executed? – mkirci Feb 06 '13 at 19:04
1

I see a couple issues. First of all, your custom setter will not be called when you add an object to your data array. It will only be called when you create the NSArray itself, not add or remove entries from the array. So you should scrap your custom setter and call reloadData in your addCurrentItemToCartFromNotification notification.

Also, you should add the observor in viewDidLoad and remove it in viewDidUnload, not awakeFromNib (which is not called in certain situations).

Joel
  • 15,654
  • 5
  • 37
  • 60
  • Good catch on the setter method! - But `viewDidUnload` is not a good place for unregistering observers, because that method is not called anymore in iOS 6. – Martin R Feb 06 '13 at 18:25
  • Interesting. I haven't done any iOS 6 projects yet so that is news to me. Good point. So is it now handled on dealloc? – Joel Feb 06 '13 at 18:29
  • @Joel - I tried your suggestions: a) all reload data in "addCurrentItemToCartFromNotification" and b)moving observer from AwakeFromNib to ViewDidLoad a) - worked but moving the observer to ViewDidLoad did not help. However, point a) + having the observer in AwakeFormNib is working. The Notified Item is now being displayed in my tableview. Thanks! But however, I am now facing another issue which I am posting as an edit to my question above due to space contraint. Appreciate if you could throw you inputs on that one. Thanks! – Mike G Feb 06 '13 at 18:34
  • @Joel: Have a look at [Managing Memory Efficiently](http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html#//apple_ref/doc/uid/TP40007457-CH10-SW10) in the "View Controller Programming Guide for iOS". `dealloc`, `didReceiveMemoryWarning` and `viewWill/DidDisappear` can be suitable places to release resources. – Martin R Feb 06 '13 at 18:36
  • You probably wouldn't want to remove an observer on viewDidDisappear as you will then miss messages while the view is alive, so sounds like he should do it on dealloc. – Joel Feb 06 '13 at 18:42
  • Just create your NSMutableArray on init or viewDidLoad and release it on dealloc (if not using ARC) and you will be fine. – Joel Feb 06 '13 at 18:44
  • And get rid of your custom setters and getters and any property declarations. It's fine as an ivar. So remove "self" as well when accessing it (unless you are exposing it publicly which you haven't mentioned). – Joel Feb 06 '13 at 18:46
  • @Joel - tried adding it in ViewDidLoad and it did not work. So When you say init, do I create a new method called init int he tableviewcontroller? – Mike G Feb 06 '13 at 18:49
  • http://stackoverflow.com/questions/743010/which-initializers-to-override-for-uitableviewcontroller-subclass – Joel Feb 06 '13 at 18:52
  • When you created the view, was there not a stub there provided for the initWithNibName method? Generally there is a stub with a comment saying something like //do any custom initialization here – Joel Feb 06 '13 at 18:54
  • @Joel - I moved the chunk of code hat does the alloc init of my property over from my "addCurrentItemToCartFromNotification" method to initWithNibName but still not working. Now nothing shows up in my table view. I think the NSMutableArray is not alloc init ed at all. '- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{ if (!self.cart){ NSLog(@"self.cart == nil"); self.cart = [[NSMutableArray alloc] init]; }else{ NSLog(@"self.cart != nil"); } return self; }' – Mike G Feb 06 '13 at 20:42
  • There is something else going on if it's not working. Like I said, don't make cart a property. Make it an ivar only. And remove all the self.cart references and just access cart directly. And log when you initialize it to confirm that it is being initialized. – Joel Feb 06 '13 at 20:46
  • Also on init you don't need to check if it is nil. Just do cart = [[NSMutableArray alloc] init]; – Joel Feb 06 '13 at 20:48