Passing data with delegate but still nil why? - ios

I made 2 viewcontrollers and implemented on tabbar controller. I passed some data from A vc to B vc with using delegate. When I checked the log it showed me correct value. But when I moved to B vc the value I passed was nil. (the value is for tableview.) Here is my code.
in A vc
-(void)passData {
NSMutableDictionary *infoDic = [[NSMutableDictionary alloc] init];
[infoDic setObject:url forKey:#"file_url"];
[downloadArr addObject:fileInfoDic];
Bvc getDataFromA:downloadArr];
[Bvc reloadTableView];
}
in B vc
-(void)getDataFromA:(NSMutableArray *) downloadArr{
self.downloadArr = [downloadArr mutableCopy];
NSLog(#"my download list%#", self.downloadArr); // This time was ok.
}
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
NSLog(#"Array status %#", self.downloadArr);//This time it showed me nil
[self.tableView reloadData];
}

To have the array printed inside viewWillAppear without nil
NSLog(#"Array status %#", self.downloadArr);//This time it showed me nil
you need to give it a value before you show bVC from aVC , whatever you use present/segue/push , also don't forget to declare it as strong , you need to do this
bvc = [[self.tabBarController viewControllers] objectAtIndex:1];
[bvc loadViewIfNeeded];
[bvc getDataFromA:downloadArr];

Please check the way you move to B-VC and whether the instance of (B-VC) you used in the A -VC is same to self in the B-VC “viewWillAppear” method.
It seems when u move to B-VC, A new instance has been created.
Or you can implement the 'setDownloadArr' method, log the value and show when the value become nil.

Related

Changing date not reflected in previous view

I am reading some book and I stumbled this thing.
In my ViewController when a user clicks change date button following
code is called:
- (IBAction)changeDate:(id)sender {
DateViewController *vc = [[DateViewController alloc] init];
[vc setItem: item];
[[self navigationController] pushViewController:vc animated:YES];
}
item is a pointer to a custom class object, which has ivar of type NSDate *;
Now, inside DateViewController when user already picked new date and wants
to navigate to previous view, I have following code:
- (void)viewWillDisappear:(BOOL)animated
{
NSLog(#"%#", [datePicker date]);
item.dateCreated = [datePicker date]; // get selected date
}
This code works and when user goes back from above code change is reflected
in item data structure and user can see new date. However, if I change above code, to following code, it doesn't work anymore, any clues why?
(This does NOT work):
- (IBAction)changeDate:(id)sender {
DateViewController *vc = [[DateViewController alloc] init];
vc.userDate = currentItem.dateCreated;
[[self navigationController] pushViewController:vc animated:YES];
}
DateViewController:
- (void)viewWillDisappear:(BOOL)animated
{
NSLog(#"%#", [datePicker date]);
self.userDate = [datePicker date];
}
In the first case, item is a mutable instance, because you can change the date that it contains. In the second case you are supplying the NSDate itself, which is immutable.
So, in the first case, you pass a reference to item which can be edited and these edits are available later.
But, the second case doesn't edit the original date, it just stores the chosen date into a property on the view controller which is in the middle of being dismissed.
Generally it is better to make the communication clear, so the view controller would pass the chosen date back to the caller by delegation or provide a property (like in your second case) that can be queried once the selection is made. Your first option is effectively hiding the data exchange by sharing the instance item while the second view controller is on display.
Immutable means that the object itself (its contents) can not be changed. It does not prevent any reference to the object from being changed. If we use arrays (where there are mutable an immutable versions) to demonstrate:
NSArray *a = [NSArray array];
NSArray *b = a;
[b editSomething]; // illegal (not a true method name but just an example of something you might want to try)
b = nil; // just nils b, no affect on a at all
And
NSMutableArray *a = [NSArray array];
NSMutableArray *b = a;
[b addObject:#"String"]; // edits a, because a and b are the same object
b = nil; // just nils b, no affect on a at all
The NSArray is like the situation where you just pass the NSDate. The NSMutableArray is like the situation where you pass item (because you can change the contents).

iOS - Changing tabbar badge from other class

I've searched a lot but could not find an answer and therefore decided to ask you :).
I have an application with some views. After logging in I create a UITabBarController with 3 tabs.
Now I wish to change the second tab's badge based on how many notifications the user has.
This core works when called in the viewdidload method:
NSString *badgeValue = [NSString stringWithFormat:#"%i", [cacheNotifications count]];
if([cacheNotifications count] != 0){
[[[[[self tabBarController] viewControllers] objectAtIndex: 1] tabBarItem] setBadgeValue:badgeValue];
}
However, I have a daemon running in the background that checks for notifications every 30 seconds. It would be great if I could change the badge from this daemon.
When I call something like this:
PlatformViewController *theInstance = [[PlatformViewController alloc] init];
[theInstance updateNotificationsBadge];
It does call the function but does not update the badge. With or without the performSelectorOnMainThread.
updateNotificationsBadge:
-(void) updateNotificationsBadge{
NSString *badgeValue = [NSString stringWithFormat:#"%i", [cacheNotifications count]];
NSLog(#"Length here is: %i", [cacheNotifications count]);
if([cacheNotifications count] > 0){
NSLog(#"call..");
[self performSelectorOnMainThread:#selector(setNotification:)
withObject:badgeValue
waitUntilDone:YES];
}
}
-(void)setNotification:(NSString*)badge{
NSLog(#"Called. %#", badge);
[[[[[self tabBarController] viewControllers] objectAtIndex: 1] tabBarItem] setBadgeValue:badge];
}
How could I fix this?
Thanks in advance!
EDIT:
cacheNotifications is a global variable declared in globalVars.m. It does not get reinitialized when I call a new instance.
I call the code below from daemonClass.m
PlatformViewController *theInstance = [[PlatformViewController alloc] init];
[theInstance updateNotificationsBadge];
Instead of creating a new instance for platformViewController, you need to use existing reference. When you create a new one, cacheNotification array would not be initialized and no contents in it. So it will always returns 0.
and UITabBarController is a containerViewController contains all the viewControllers. So you don't need to change the tab badgeValue from the other class. You can simply change it from any class.
and in your setNotification: method, change the badgeValue like this.
[[[[self tabBarController] tabBar] items] objectAtIndex:1] setBadgeValue:badge];
You should use the same instance of class rather creating the new one. Which destroy the previous value. I would recommend please use NSNotificationCenter to post notification when you get a badge which will implement void getter and setter method of badge in platformViewControllerclass. then no instance would be destroy.
Hope this helps
I really don't know exactly your problem, but what I think I would use a subclass of nsobject and in each viewController I'd change the badge. Something similar to this: https://stackoverflow.com/a/9736559/2000162
func setBadge(){
let viewconrollers = self.tabBarController?.viewControllers
viewconrollers![3].tabBarItem.badgeValue = "Your String value"
viewconrollers![3].tabBarItem.badgeColor = UIColor.green
}
//call setBadge() method from view controller's viewdidload method.
// select your give number it the view controllers array for providing badge on the desired tab

Object creation of views and share data between view in iOS

I am new to iOS.I am recently stuck with a problem.
I have a view A and View B. View A has a navigation controller. view A has a button to switch to B.When i am clicking this button every time B creates a new object. how can i track this object to share data between this two view.
Thanks
There are several ways to do this.
You could have a property of B, that A sets before you push. (NSDictionary, Array, String etc)
This not the best way however it would work.
UIViewController *viewB = [[UIViewController alloc]init];
[viewB setMyProperty:#"some data!"];
[self.navigationController pushViewController:viewB animated:YES];
You could also use NSNotificationCenter to pass the object to the next view.
NSDictionary *dictionary = [NSDictionary dictionaryWithObject:
[NSNumber numberWithInt:index]
forKey:#"index"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"myNotification"
object:self
userInfo:dictionary];
The way I usually handle this is to setup and object that holds my data with an associated protocol initialized in my AppDelegate. Then any view that needs to read/write something just grabs a Pointer to that object and runs with it.
#class AppData;
#protocol AppDataProtocol
- (AppData*)theAppData;
#end
in the View you can grab the pointer with this.
-(AppData*)theAppData {
id<AppDataProtocol> theDelegate = (id<AppDataProtocol>)[UIApplication sharedApplication].delegate;
AppData* theData = (AppData*)theDelegate.theAppData;
return theData;
}
and this.
appData = [self theAppData];
You are then able to easily access any property of appData.
-(void)fnButtonA{
ViewB *vcB = [[ViewB alloc] initWithData:DataToB];
[[self navigationController] pushViewController:vcB animated:Yes];
}
In ViewB.m edit the init function to
-(UIViewController *)initWithData:(NSMutableDictionary*)data

Passing NSArray from DidSelectRow of a table to another UITableview

I am trying to pass an array from one table ,and populate it in another table.The parent table is place upon a UINavigationController say "mainNavig".The child table is placed in another ViewController of name "SongsofAlbum".My didSelectRowAtIndexPath of parent table is as follows,
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
albumName = [eliminateDupe objectAtIndex:indexPath.row];
temp = [dictforalbum allKeysForObject:albumName ];
songs = [NSMutableArray arrayWithCapacity:[temp count]];
for (NSString *filename in temp) {
[songs addObject:[[filename lastPathComponent] stringByDeletingPathExtension]];
}
NSLog(#"songs are %#",songs);
songObj = [[SongsofAlbum alloc]initWithNibName:#"SongsofAlbum" bundle:nil];
[mainNavig pushViewController:songObj animated:YES];
songObj.albumname = albumName;
songObj.songArray = songs;
NSLog(#"the song object array is %# ",songObj.songArray)
}
The nslog of songObj.songArray returns the data in the above method .But the problem I face is ,when I call this songArray in the child view controller it returns NULL . I even property synthesized the arrays. Any suggestions?
But the problem I face is ,when I call this songArray in the child
view controller it returns NULL . I even property synthesized the
arrays.
In other ViewController you are creating a new instance of this class. The new instance will be NULL.
You do not need to create new instance infact you need to use this same object's value from there.
You can do this thing by: How to make button in child view to update information in its parent view?
You can take your songs array in AppDelegate and then instead assigning songObj.songArray = songs you can assign it in your SongsofAlbum class's viewDidLoad like
AppDelegate *app;
- (void)viewDidLoad
{
[super viewDidLoad];
app=(AppDelegate *)[[UIApplication sharedApplication]delegate];
songarray= [[NSMutableArray alloc]initWithArray:app.songs];
}
Hope this will work.

Passing a MutableArray between ViewControllers

BookingDocumentsViewController *bdVc = [self.storyboard instantiateViewControllerWithIdentifier:#"BookingDocs"];
bdVc.orId = rl_id;
bdVc.docsArray = self.documentsArray;
[self.navigationController pushViewController:bdVc animated:YES];
I have Above code snippet. I'm trying to load a new viewcontroller and assign its Mutable Array (docsArray) object to current view's mutableArray (documentsArray <=this is not nil)
Whenever I execute above code I get EXC_BAD_ACCESS error.
but if I comment the 3rd line. It works but I can't get my array to the new view. I even tried with [[NSMutableArray alloc] initWithArray:self.documentsArray]; this doesnt work either.
But if I use bdVc.docsArray =[[[NSMutableArray alloc] init]; it works but again I can't get my mutable array to the new view.
Edit:
However 2nd line has NSString values. And they can be passed without a problem.
What am I doing wrong here?
I'm not getting any errors in console, instead I get this.
Maybe consider using a Segue. It instantiates the destination viewcontroller for you. Then in your source view controller implement
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
Get a reference to your destination viewcontroller and set its data.
BookingDocumentsViewController *bdVc = [segue destinationViewController];
bdVc.docsArray = self.documentsArray;
in BookingDocumentsViewController.h
#property(nonatomic, retain)NSmutableArray *docsArray;
You do can do in your BookingDocumentsViewController.m:
#synthesize docsArray;
- (void)viewDidLoad
{
NSmutableArray *array = [NSmutableArray alloc]initWithArray:docsArray];
[super viewDidLoad];
}
then when you are pushing the view
BookingDocumentsViewController *bdVc = [self.storyboard instantiateViewControllerWithIdentifier:#"BookingDocs"];
bdVc.orId = rl_id;
bdVc.docsArray = self.documentsArray;
[self.navigationController pushViewController:bdVc animated:YES];
[bdVc Release];
I think I found the issue. A very basic mistake. In bdVc's viewDidLoad I had the following line,
NSLog(#"Booking Documents viewDidLoad : %#",self.docsArray.count);
This was causing the error. that %# instead of %d. I wonder why xcode didn't show proper reason for the error.
Thank you all for the help. :)

Resources