How do i pass info from loginViewFetchedUserInfo: to multiple views at once - ios

Hi i am trying to pass the user.id and user.name from loginViewFetchedUserInfo: to my menuViewController, profileViewController and settingViewController so far i have sent the info to profileViewController with:
// this method will be called when the user information has been fetched
- (void)loginViewFetchedUserInfo:(FBLoginView *)loginView user:(id<FBGraphUser>)user
{
// self.profilePictureView.profileID = user.id;
//self.FBProfilePicture.profileID = user.id;
_profilePicture = user;
_FBNameString = user.name;
NSLog(#"%#, name from Login", _FBNameString);
[self pushViewController:user.name andProfilePicture:_profilePicture];
}
- (void)pushViewController:(NSString *)userName andProfilePicture:(id<FBGraphUser>)profilePicture
{
// MenuViewController *menu = [self.storyboard instantiateViewControllerWithIdentifier:#"MenuViewController"];
// [menu setFBName:userName];
// [menu setFBProfilePic:profilePicture];
//
// SettingViewController *setting = [self.storyboard instantiateViewControllerWithIdentifier:#"SettingViewController"];
// [setting setFBName:userName];
// [setting setFBProfilePic:profilePicture];
// NSLog(#"%#",profilePicture);
// [self.navigationController pushViewController:controller animated:NO];
}
and i can only receive the info in the profileViewController and not the other i have put setters and getters i'm using protocols but i'm not able to get it to another viewController

In general you method should be like this.(you may need to tweak as per requirement)
// this method will be called when the user information has been fetched
-(void)loginViewFetchedUserInfo:(FBLoginView *)loginView user:(id<FBGraphUser>)user{
// self.profilePictureView.profileID = user.id;
//self.FBProfilePicture.profileID = user.id;
_profilePicture = user.picture;//assuming you may be having picture property for object user
_FBNameString = user.name;
NSLog(#"%#, name from Login", _FBNameString);
//POST NOTIFICATION with desire object here its "user"
[[NSNotificationCenter defaultCenter] postNotificationName:#"POSTLOGININFO" object:user];
//uncomment if you want this, ...depends on you
//[self pushViewController:user.name andProfilePicture:_profilePicture];
}
Now update init method of your menuViewController.m, profileViewController.m and settingViewController.m class like below
-(id) init
{
self = [super init];
if (!self)
return nil;
//Your custom code
//get registered for POSTLOGININFO notification so that selector method get called when you post notification with name POSTLOGININFO
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(gotLoginInfo:)
name:#"POSTLOGININFO"
object:nil];
return self;
}
Add new method gotLoginInfo: to each of your menuViewController.m, profileViewController.m and settingViewController.m
-(void)gotLoginInfo:(NSNotification *)notification{
//Assuming FBGraphUser class have all required properties
FBGraphUser *user = (FBGraphUser *)[notification object];
// save user.id and user.name to your class local variable
NSLog(#"UserID::%# and username::%#",user.id,user.name);
}
-(void)dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"POSTLOGININFO" object:nil];
}
remove notification observer once you are done by using
"[[NSNotificationCenter defaultCenter] removeObserver:self name:#"POSTLOGININFO" object:nil];". Also be sure to have valid objects of your class menuViewController, profileViewController and settingViewController before loginViewFetchedUserInfo: get called

You can use NSNotification.
Example
There is a method named myTestNotificationReceived which is implemented in myClassA. Now I want to call this method from another class myClassB. Below is the code how I can do this using NSNotificationCenter.
#implementation myClassA
- (void) dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
- (id) init
{
self = [super init];
if (!self) return nil;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(myTestNotificationReceived:)
name:#"myTestNotification"
object:nil];
return self;
}
- (void) myTestNotificationReceived:(NSNotification *) notification
{
if ([[notification name] isEqualToString:#"myTestNotification"])
NSLog (#"Notification is successfully received!");
}
#end
Now I want to call the method myTestNotification from myClassB.
#implementation myClassB
- (void) dealloc{
[super dealloc];
}
- (id) init
{
self = [super init];
if (!self) return nil;
return self;
}
- (void) myMethod
{
// All instances of myClassA will be notified
[[NSNotificationCenter defaultCenter]
postNotificationName:#"myTestNotification"
object:self];
}
#end
Now you can add as many observer in your different classes.

Related

How to initialise a VC or Class iOS, ObjectiveC

When a button is clicked at FirstVC, it will pass data and trigger SecondVC using NSNotificationCenter
During initial launch of the app, because SecondVC has not been initialize yet, so data cannot be passed to SecondVC. NSNotificationCenter cannot function properly. Only after SecondVC has been initialize, NSNotificationCenter will function correctly.
So I need to initialise SecondVC somewhere. Will it be at - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions?
Or how do I programatically call the tab of SecondVC.
FirstVC
#import "Search.h"
#import "Classes.h"
#import "MyTabBarController.h"
#interface Search(){
AppDelegate *appDelegate;
CERangeSlider* _rangeSlider;
NSString *sURL, *strResult, *sRemaining, *sStartTime, *sEndTime, *sSelectedLat, *sSelectedLong;
}
#end
#implementation Search
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (IBAction)btnSearch:(UIButton *)sender {
self.tabBarController.selectedIndex = 1;
sURL = #"Testing 123";
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:sURL forKey:#"theURL"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"toClasses" object:nil userInfo:userInfo];
}
#end
Second VC
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(receiveTestNotification:)
name:#"toClasses"
object:nil];
dtDate = [[NSMutableArray alloc] init]; //=== Mutable array to store the dates generated
self.currentPageIndex = 0;
[self setupSegmentButtons];
NSDate *now = [NSDate date];
NSDateFormatter *dateFormatter=[[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd/MM/YYYY"];
sDtDate = [dateFormatter stringFromDate:now];
[self LoadClasses];
}
-(void)viewWillAppear:(BOOL)animated {
//--- Hide the Top Navigation Controller Bar at the current View
[[self navigationController] setNavigationBarHidden:YES animated:YES];
}
//--- Top Navigation Controller reappear on the next VC
-(void)viewDidDisappear:(BOOL)animated{
[[self navigationController] setNavigationBarHidden:NO animated:YES];
}
-(void) receiveTestNotification:(NSNotification*)notification
{
if ([notification.name isEqualToString:#"toClasses"])
{
NSDictionary* userInfo = notification.userInfo;
NSLog (#"Successfully received userInfo! %#", userInfo);
NSString* sFromSearch = [NSString stringWithFormat: #"%#", userInfo];
NSLog (#"Successfully received test notification! %#", sFromSearch);
}
}
In my opinion, you don't need to use notification or singleton on this case.
Simply, get SecondViewController from self.tabBarController and call the method.
First VC
- (IBAction)btnSearch:(UIButton *)sender {
self.tabBarController.selectedIndex = 1;
sURL = #"Testing 123";
UINavigationController* secondNav = (UINavigationController*)self.tabBarController.viewControllers[1];
SecondViewController* secondViewController = [secondNav.viewControllers firstObject];
[secondViewController handleString:sURL];
}
Second VC
- (void)handleString:(NSString*)string {
// Do whatever you want with string passed from First VC
}
You added observer in viewDidLoad, so it will not work even you create it before user tap on button and send notification. because observer will not be registered. I advise you not use observer to send data in this case. you can save this data elsewhere and use it when seconVC will load. for example in singleton object.
your Singleton object looks like this:
Interface:
#interface DataManager : NSObject
#property (nonatomic, strong) NSDictionary *userInfo;
+ (DataManager *) getInstance;
#end
Implementation:
#implementation DataManager
+ (DataManager *) getInstance {
static DataManager *appManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
appManager = [[DataManager alloc] init];
});
return appManager;
}
#end
Now you can access this object where you want and you can assured that only one instance is created.
here is your button click method:
- (IBAction)btnSearch:(UIButton *)sender {
self.tabBarController.selectedIndex = 1;
sURL = #"Testing 123";
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:sURL forKey:#"theURL"];
[DataManager getInstance].userInfo = userInfo;
}
and your viewDidLoad in secondVC
- (void)viewDidLoad {
[super viewDidLoad];
NSDictionary *userInfo = [DataManager getInstance].userInfo;
}

NSNotification postNotification and addObserver

I am trying to do a notification from a location manager object to my viewController. It's not working - the selector in the addObserver method doesn't get called.
Location Manager Object.m files (singleton with standard dispatch once & init methods)
- (void)setCurrentLocation:(CLLocation *)currentLocation
{
if (!_location) {
_location = [[CLLocation alloc] init];
}
_location = currentLocation;
NSNumber *latitude = [NSNumber numberWithDouble:self.location.coordinate.latitude];
NSNumber *longitude = [NSNumber numberWithDouble:self.location.coordinate.longitude];
NSLog(#"lat %# & long %# in notification section", latitude, longitude);
NSNotification *notification = [NSNotification notificationWithName:#"myNotification" object:self userInfo: #{kSetLat: latitude,
kSetLong: longitude}];
[[NSNotificationCenter defaultCenter] postNotification:notification];
}
ViewController.m (garden variety)
- (IBAction)welcomeNotification:(UIButton *)sender {
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:#selector(sendGetRequest:) name:#"myNotification" object:[LPLocationManager sharedManager]];
[center removeObserver:self];
NSLog(#"welcomeNotication triggered");
}
The way you do is not correct. Why you add the observer and then remove it immediately. Most of the time, we add/remove observer in viewWillAppear and viewWillDisappear or viewDidAppear and viewDidDisappear.
It should be something like:-
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(sendGetRequest:) name:#"myNotification" object:nil];
}
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"myNotification" object:nil];
}

Update UI from another class

I am trying to separate my GUI and my Logic...For example, i have one class which calculates something (calc.h/calc.m). And i have my GUI (viewController.h/viewController.m)...Now i want to update one Element of the GUI from another class... I already tried it with a Singleton, like this:
calc.m:
viewController *con = [viewController sharedInstance];
con.download.text = #"It Works";
viewController.m:
+ (id)sharedInstance {
static id sharedInstance;
#synchronized(self) {
if (!sharedInstance)
sharedInstance = [[viewController alloc] init];
return sharedInstance;
}
}
But it does´t work...
UPDATE:
in my ViewController:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveNotification:)
name:#"UpdateDownloadLabel"
object:nil];
- (void) receiveNotification:(NSNotification *) notification
{
NSDictionary* userInfo = notification.userInfo;
if ([[notification name] isEqualToString:#"Update"])
{
download.text = [userInfo valueForKey:#"Test"];
}
}
And in my other class i post the notification like this:
[[NSNotificationCenter defaultCenter]
postNotificationName:#"UpdateDownloadLabel"
object:nil userInfo:info];
But it doesn't work...
That's not a proper use of a singleton. If you need to notify your UI from your model you have these options:
- delegation
- Local Notification
- KVO
The general rule is to keep your logic decoupled from your presentation, therefore your calc class shouldn't really know that a label named download exists.
Example: How to use notification.
In classA.h file
extern NSString * const ClassADidViewNotification;
In classA.m file
NSString * const ClassADidViewNotification = #"ClassADidViewNotification";
Register for notification in classA.m :-
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserverForName: XXFooDidBarNotification
object:nil
queue:nil
usingBlock:^(NSNotification *notification)
{
NSLog(#"notification.object: %#", notification.object);
}
];
Post Notification:-
ClassB.m
[[NSNotificationCenter defaultCenter] postNotificationName: ClassADidViewNotification object:nil];

Where is the best place to remove Observer from Notification Center

I think that should be here:
-(void) viewWillDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc removeObserver:self];
}
or maybe in -dealloc.
Both sound strange to me so I´m not totally sure of it.
First, in my AppDelegate I´m listening to a Remote Notification Via Parse
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo {
[PFPush handlePush:userInfo];
NSString * urlToGo = [userInfo objectForKey:#"url"];
NSLog (#"Recibo notificación con paremetro url: %#", urlToGo);
NSNotification *note = [NSNotification
notificationWithName:PUSH_NOTIFICATION
object:self
userInfo:userInfo];
[[NSNotificationCenter defaultCenter] postNotification:note];
}
and in myViewController
- (void) viewDidLoad {
[super viewDidLoad];
_lastMenuSelected=menu1;
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
[center addObserverForName:PUSH_NOTIFICATION
object:nil
queue:mainQueue
usingBlock:^(NSNotification *note) {
// Save in property to load parameter in prepareForSegure
_urlToLoadFromPush = urlToGoReceivedFromPush;
[self showPush:self];
}];
}
- (void)showPush:(id)sender {
PushViewController * pushViewController=(PushViewController*)[self.storyboard instantiateViewControllerWithIdentifier:#"PushId"];
pushViewController.url = _urlToLoadFromPush;
UINavigationController* nVC=[[UINavigationController alloc] initWithRootViewController:pushViewController];
[self presentViewController:nVC animated:YES completion:^{
//[_delegate logout];
}];
}
Since you seem to be adding the observer in the viewDidLoad method (which is only called once as of iOS 6), you should remove the observer in the dealloc method.
Don't remove the observer in viewWillDisappear beacause generally we require to post the notification when the view is in the stack but not appearing. So always try to remove the observers in -(void)dealloc with the name of observer.

Unable to receive notification

I try to send local notification. Here some code for class sending the notification:
#interface Sender : UIView
{
NSInteger itemID;
}
#implementation Sender
-(void) changedProperty
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"NotificationName" object:NULL];
}
And here the code to receive this notification:
#interface Listener : UIViewController
{
}
#implementation Listener
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(selectedItem:) name:#"NotificationName" object:NULL];
}
- (void)viewDidUnload
{
[super viewDidUnload];
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"NotificationName" object:NULL];
}
-(void) selectedItem:(NSNotification *) notification
{
// some actions
}
But this code doesn't work. Debugging I see how postNotificationName: object works but the method selectedItem: doesn't call
UPDATE.
Here is more code. Maybe this will help.
extern const NSString* selectItemNotificationName;
#interface vRoomSelectorItem : UIView
{
RoomSelectorItemBackground backgroundType;
NSInteger itemID;
}
#property NSInteger itemID;
-(void) setBackgroundType:(RoomSelectorItemBackground) backgroundType;
#interface vRoomSelectorItem ()
#property RoomSelectorItemBackground backgroundType;
#end
#implementation vRoomSelectorItem
const NSString* selectItemNotificationName = #"Reservation.SelectRoom";
-(RoomSelectorItemBackground) backgroundType
{
return backgroundType;
}
-(void) setBackgroundType:(RoomSelectorItemBackground)value
{
if(backgroundType != value)
{
backgroundType = value;
[self changedBackgroundType];
}
}
-(void) changedBackgroundType
{
if(backgroundType == RoomSelectorItemFilled)
{
// animation
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:(NSString*)selectItemNotificationName object:NULL userInfo:[[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithInteger:itemID], #"ID", NULL]];
});
}
else
// reverse animation
}
#import "vRoomSelectorItem.h"
#interface vcReservationSelectRoom : UIViewController
{
NSMutableArray* arraySelectorItems;
}
#implementation vcReservationSelectRoom
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(selectedItem:) name:(NSString*)selectItemNotificationName object:NULL];
for(NSInteger i = 1; i <= SELECTOR_ITEM_COUNT; ++i)
{
vRoomSelectorItem* newItem = [[vRoomSelectorItem alloc] initWithFrame:CGRectMake(/*coordinates*/)];
[self.view addSubview:newItem];
[newItem setBackgroundType:RoomSelectorItemTransparent];
[newItem setItemID:i];
[arraySelectorItems addObject:newItem];
newItem = NULL;
}
}
-(void) selectedItem:(NSNotification *) notification
{
// some actions
}
-(void) dealloc
{
arraySelectorItems = NULL;
[[NSNotificationCenter defaultCenter] removeObserver:self name:(NSString*)selectItemNotificationName object:NULL];
}
#end
From your code in the quetion I think you can try this:
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(selectedItem:) name:#"NotificationName" object:NULL];
[self.view changedProperty]; // method of your Sender class
}
It seems like your code should work. Make sure the notification is on the main thread and the workflow is as follows:
Add listener to notification center
Initiate sender
Send notification
You can be sure that it is on the main thread with:
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] post...];
});
Couple things I would change:
remove yourself from NSNotificationCenter in -(void)dealloc instead
of -(void)viewDidUnload. viewDidUnload will be deprecated, and
dealloc could get called without viewDidUnload.
For Notifications, I like to store the name in an external constant
to make sure that I don't typo the string:
//header.h
extern NSString *const notificationName;
//implementation.m
NSString *const notificationName = #"notification";
Ok, I've solved the problem. The piece of code above is not enough to understand, why it has not been working. The object of class vcReservationSelectRoom was temporary and it had been destroyed before sending notification from any vRoomSelectorItem. Sorry for my mistake of not showing enough code to solve this problem. And thank you all for helping.

Resources