I have implemented iOS slide menu navigation controller in my app and its working fine earlier. But somehow now its left menu view controllers is coming black screen. Please suggest if someone faced this issue. Below code I have mentioned in Appdelegate.m didFinishLaunchingWithOptions.
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main"
bundle: nil];
self.navigationController = (UINavigationController*)[mainStoryboard
instantiateViewControllerWithIdentifier: #"navBar"];
self.landingScreen = (SlideNavigationController*)[mainStoryboard
instantiateViewControllerWithIdentifier: #"FirstViewController"];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
LeftMenuViewController *leftMenu = (LeftMenuViewController*)[mainStoryboard
instantiateViewControllerWithIdentifier: #"LeftMenuViewController"];
self.landingScreen = [SlideNavigationController sharedInstance];
self.landingScreen.leftMenu = leftMenu;
// Creating a custom bar button for right menu
[[NSNotificationCenter defaultCenter] addObserverForName:SlideNavigationControllerDidClose object:nil queue:nil usingBlock:^(NSNotification *note) {
NSString *menu = note.userInfo[#"menu"];
NSLog(#"Closed %#", menu);
}];
[[NSNotificationCenter defaultCenter] addObserverForName:SlideNavigationControllerDidOpen object:nil queue:nil usingBlock:^(NSNotification *note) {
NSString *menu = note.userInfo[#"menu"];
NSLog(#"Opened %#", menu);
}];
[[NSNotificationCenter defaultCenter] addObserverForName:SlideNavigationControllerDidReveal object:nil queue:nil usingBlock:^(NSNotification *note) {
NSString *menu = note.userInfo[#"menu"];
NSLog(#"Revealed %#", menu);
}];
Earlier one mistake by replacing the NSLog with //**NSLog is the issue which is replaced the NSlog in the SlideNavigationController.m
//Earlier
if (singletonInstance)
//**NSLog(#"Singleton instance already exists. You can only instantiate one instance of SlideNavigationController. This could cause major issues");
//After removing this //** from the NSLOG now its working fine
if (singletonInstance)
NSLog(#"Singleton instance already exists. You can only instantiate one instance of SlideNavigationController. This could cause major issues");
Thanks to Bond and Keyur to giving their feedbacks.
Related
In Appdelegate.m added postNotification method
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
if(application.applicationState == UIApplicationStateBackground) {
[[NSNotificationCenter defaultCenter] postNotificationName: #"SuggetionPushNotification" object:nil userInfo:userInfo];
AppDelegate *appDel = (AppDelegate *)[[UIApplication sharedApplication] delegate];
SideMenuViewController *leftMenuViewController = [[SideMenuViewController alloc] init];
MFSideMenuContainerViewController *container = [MFSideMenuContainerViewController
containerWithCenterViewController:[[UINavigationController alloc]
initWithRootViewController:[[SuggetionViewController alloc] init]]
leftMenuViewController:leftMenuViewController
rightMenuViewController:Nil];
[self.window makeKeyAndVisible];
appDel.window.rootViewController = container;
}
}
ViewController B (SuggetionViewController) In viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveTestNotification:)
name:#"SuggetionPushNotification"
object:nil];
- (void) receiveTestNotification:(NSNotification *) notification {
NSLog(#"working");
}
But here not yet fire Notification, if added both post and addobserver in same class then only it fire. what wrong i made. I referred from Send and receive messages through NSNotificationCenter in Objective-C? Please help
Your View Controller B is not in memory when you are posting the notification thats why Controller B is unable to observe the notification. Add Delay before posting the notification will help.
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[[NSNotificationCenter defaultCenter] postNotificationName: #"SuggetionPushNotification" object:nil userInfo:nil];
});
You're calling your notification from the launch method in the app delegate before any view/viewcontroller hierarchy has a change to instantiate and load. The reason you are not getting the notification is because your SuggetionViewController has not been instantiated yet. If you want the notification to be received, you need to fire it after the view controller gets a change to be created.
You can't receive notification inside your SuggetionViewController if it's now loaded.
You add the observer in the viewDidLoad so it can happens that you recieve a remote notification while the SuggetionViewController is not loaded.
You should ensure that your controller is loaded before processing notifications.
In your AppDelegate implementation add this
static void displayStatusChanged(CFNotificationCenterRef center, void *observer,
CFStringRef name, const void *object,
CFDictionaryRef userInfo) {
if (name == CFSTR("com.apple.springboard.lockcomplete")) {
[[NSUserDefaults standardUserDefaults] setBool:YES
forKey:#"kDisplayStatusLocked"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
In applicationDidFinishLaunchingWithOptions, add this below code
CFNotificationCenterAddObserver(
CFNotificationCenterGetDarwinNotifyCenter(), NULL, displayStatusChanged,
CFSTR("com.apple.springboard.lockcomplete"), NULL,
CFNotificationSuspensionBehaviorDeliverImmediately);
Post it in your didRecieveRemoteNotification method.
[[NSNotificationCenter defaultCenter]postNotificationName:#"TestNotification" object:self];
Post this in your view controller viewDidLoad method.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveTestNotification:)
name:#"TestNotification"
object:nil];
Then it will trigger this method.
- (void) receiveTestNotification:(NSNotification *) notification
{
if ([[notification name] isEqualToString:#"TestNotification"]) {
NSLog (#"Successfully received the test notification!");
}
}
Your 'SuggetionViewController' object is not initialized when you post the notification. So there is no 'SuggetionViewController' object to catch the notification.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
if(application.applicationState == UIApplicationStateBackground) {
AppDelegate *appDel = (AppDelegate *)[[UIApplication sharedApplication] delegate];
SideMenuViewController *leftMenuViewController = [[SideMenuViewController alloc] init];
SuggetionViewController *sug_controller = [[SuggetionViewController alloc] init]];
[sug_controller registerNotification];
[[NSNotificationCenter defaultCenter] postNotificationName: #"SuggetionPushNotification" object:nil userInfo:userInfo];
MFSideMenuContainerViewController *container = [MFSideMenuContainerViewController containerWithCenterViewController:[[UINavigationController alloc] initWithRootViewController:sug_controller leftMenuViewController:leftMenuViewController rightMenuViewController:Nil];
[self.window makeKeyAndVisible];
appDel.window.rootViewController = container;
}
}
Add the following instance method to SuggetionViewController
- (void)registerNotification
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receiveTestNotification:) name:#"SuggetionPushNotification" object:nil];
}
- (void)receiveTestNotification
{
NSlog(#"Notification recieved-->>>");
}
I am pretty stuck with this and hoping someone can show me some light about this.
I need help to figure out how to refresh the table list on the main view from the slide-in menu.
IN MAIN VIEW
So basically, I have a main view that has a list of events. I use this function to retrieve data from the database:
[self loadEvents:eventCat sortEvent:nil searchDate:dateSelected];
Inside that function, it has the script that gets data, determines if there is content and then reloads the table:
- (void)loadEvents:(NSString*)searchType sortEvent:(NSString*)sortType searchDate:(NSString *)dateSelect{
NSString *url = [NSString stringWithFormat: #"http://www.url.com/eventList.php];
NSURL *eventURL = [NSURL URLWithString: url];
NSLog(#"%#", eventURL);
NSData *jsonData = [NSData dataWithContentsOfURL: eventURL];
NSError *error = nil;
NSDictionary *dataDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error: &error];
self.eventList = [NSMutableArray array];
NSArray *eventArray = [dataDictionary objectForKey:#"fitpass"];
//NSString *eventFound = [dataDictionary objectForKey:#"notfound"];
//if nothing is found
if ([dataDictionary objectForKey:#"notfound"]){
tableView.hidden = YES;
noEvent.hidden = NO;
NSLog(#"123");
}else{
noEvent.hidden = YES;
tableView.hidden = NO;
NSLog(#"RELOADDATA");
for(NSDictionary *eventDictionary in eventArray){
Event *event = [Event blogPostWithTitle:[eventDictionary objectForKey:#"name"]];
event.eventTime = [eventDictionary objectForKey:#"event_time"];
[self.eventList addObject:event];
[tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];
}
}
I tried using the NSNotificationCenter method to refresh the data. So I have this in the viewDidLoad Method:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(refreshTableWithNotification:) name:#"RefreshTable" object:nil];
Then this function right after ViewDidLoad Method:
- (void)refreshTableWithNotification:(NSNotification *)notification
{
[self.tableView reloadData];
}
IN THE SLIDE MENU VIEW
In the side menu, I have a table list to populate the different categories, and when use click a category, it should refresh the event list in the main view:
//on direct press, trigger segue
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//get current value and set the eventCategory ID in userDefault
NSDictionary *catPicked = [self.catList objectAtIndex:indexPath.row];
NSString *eventCat =[catPicked objectForKey:#"ID"];
NSLog(#"%#Picked:", eventCat);
[userDefaults setObject:eventCat forKey:kEventCat];
[userDefaults synchronize];
NSLog(#"%#entered", [userDefaults objectForKey:kEventCat]);
//redirect back to eventList;
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
UIViewController *vc = [mainStoryboard instantiateViewControllerWithIdentifier: #"eventListViewController"];
//refresh data
EventLists *destinationController = [[EventLists alloc] init];
[destinationController loadEvents:eventCat sortEvent:nil searchDate:nil];
//send notofication over
[[NSNotificationCenter defaultCenter] postNotificationName:#"RefreshTable" object:nil userInfo:nil];
[destinationController.view setNeedsDisplay];
[[SlideNavigationController sharedInstance] popToRootAndSwitchToViewController:vc
withSlideOutAnimation:self.slideOutAnimationEnabled
andCompletion:nil];
return;
}
What I am stuck is that I can see the data (eventList) is updated, but the view does not refresh...
Any help would be very much appreciated!!!
Rory!!!
Thank you so much for your help!! I finally figured it out with your hint.
So basically I thought it was passing he data because of my log. But it was just merely running the function. No data was passed.
And the solution was actually rather simple. Since the data was not really being passed over, refreshing the table in the notification function will not work. The data needs to be reloaded. In other word, I just needed to change the notification function in the Main View to:
- (void)refreshTableWithNotification:(NSNotification *)notification
{
[self loadEvents:[userDefaults objectForKey:kEventCat] sortEvent:nil searchDate:dateSelected];
}
Then my Side Menu View is now much simpler since all I needed was the Notification call and view switch:
//redirect back to eventList;
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
UIViewController *vc = [mainStoryboard instantiateViewControllerWithIdentifier: #"eventListViewController"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"RefreshTable" object:nil userInfo:nil];
And yes! I needed to move the notification in the Main view to ViewDidAppear:
- (void)viewDidAppear:(BOOL)animated{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(refreshTableWithNotification:) name:#"RefreshTable" object:nil];
}
Thank you so much for your help!!
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];
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.
The App I'm trying to do has a tabbar controller.
When the App starts, I'm getting the user location in the AppDelegate and when I've got the accuracy I need the AppDelegate sends an NSNotification to my App's starting page (index 0 of the tab bar controller).
Upon receiving the notification, this view tries to send an email with the user coordinates and other data, but as soon as the MFMailComposeViewController is presented I get the following error:
Warning: Attempt to present <MFMailComposeViewController: 0x98a0270> on <UITabBarController: 0x988c630> whose view is not in the window hierarchy!
What am I missing?
Thanks.
EDIT: adding some code...
This is what I've got in my AppDelegate.m:
- (void) locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
NSUserDefaults *phoneNumbers = [NSUserDefaults standardUserDefaults];
NSDate *eventDate = newLocation.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
if (abs(howRecent) < 10.0) {
[self locationUpdate:newLocation];
smsLoc = newLocation;
if ([[phoneNumbers objectForKey:#"sendSMS"] isEqualToString:#"yes"]) {
[[NSNotificationCenter defaultCenter] postNotificationName:#"sendSMS" object:nil];
} else if ([[phoneNumbers objectForKey:#"sendEmail"] isEqualToString:#"yes"]) {
[[NSNotificationCenter defaultCenter] postNotificationName:#"sendEmail" object:nil];
}
}
}
Then, in my first view controller I have:
- (void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(sendSMS:) name:#"sendSMS" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(sendEmail:) name:#"sendEmail" object:nil];
}
And at the end, the selector for "sendSMS" (the other is pretty similar):
- (void)sendSMS: (NSNotification *)notification {
NSUserDefaults *phoneNumbers = [NSUserDefaults standardUserDefaults];
if ([phoneNumbers objectForKey:#"first"] || [phoneNumbers objectForKey:#"second"]) {
MFMessageComposeViewController *controller = [[MFMessageComposeViewController alloc] init];
if ([MFMessageComposeViewController canSendText]) {
AppDelegate *deleg = (AppDelegate *)[[UIApplication sharedApplication] delegate];
controller.body = [NSString stringWithFormat:#"some message with coordinates %.4f - %.4f", [deleg currentLocation].coordinate.latitude, [deleg currentLocation].coordinate.longitude];
controller.recipients = [NSArray arrayWithObjects:[phoneNumbers objectForKey:#"first"], [phoneNumbers objectForKey:#"second"], nil];
controller.messageComposeDelegate = self;
[self presentModalViewController:controller animated:YES];
}
}
}
}
Second edit: adding some more code.
UITabBarController *tabBarController = [[UITabBarController alloc] init];
tabBarController.delegate = self;
tabBarController.selectedIndex = 0;
[[tabBarController.tabBar.items objectAtIndex:0] setTitle:NSLocalizedString(#"Home", nil)];
[[tabBarController.tabBar.items objectAtIndex:1] setTitle:NSLocalizedString(#"Requests", nil)];
[[tabBarController.tabBar.items objectAtIndex:2] setTitle:NSLocalizedString(#"Account", nil)];
[[tabBarController.tabBar.items objectAtIndex:3] setTitle:NSLocalizedString(#"Settings", nil)];
//some other controls from DB
[[tabBarController.tabBar.items objectAtIndex:1] setBadgeValue:[NSString stringWithFormat:#"%d",number]];
The tabbarController has been made via IB, but I've added the code above in my AppDelegate because I need to localize the tab bar items and to add a badge to one of them.
Am I doing something wrong here?
I'm not sure if you have solve this issue. The error message means the viewcontroller you use to present another modal viewcontroller is not visible on the window. This can happen for e.g:
[VC1 presentModalViewController:VC2];
// Error here, since VC1 is no longer visible on the window
[VC1 presentModalViewController:VC3];
If your issue is like above, you can fix it like:
if (self.modalViewController != nil) {
[self.modalViewController presentModalViewController:VC3 animated:YES];
} else {
[self.tabBarController presentModalViewController:VC3 animated:YES];
}
If that doesn't fix your issue, maybe you can try to present using self.tabBarController instead of self. Again just suggestion, not sure if it works though.
Using this may help someone: [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:picker animated:NO completion:nil];
Since modalViewController and presentModalViewController are deprecated, the following is what works for me:
presentingVC = [[UIApplication sharedApplication] keyWindow].rootViewController;
if (presentingVC.presentedViewController) {
[presentingVC.presentedViewController presentViewController:VC3 animated:YES completion:nil];
} else {
[presentingVC presentViewController:VC3 animated:YES completion:nil];
}
You can follow this pattern
[VC1 presentModalViewController:VC2];
//
[**VC2** presentModalViewController:VC3];