Cannot change views in splitviewcontroller - cocoa-touch

I am trying to change the views in a splitview controller based upon clicking a button in a modalview (a person is selecting an option). I am using notifications to accomplish this:
When the button is clicked in the modal view, it issues a notice, then closes (dismisses) itself:
[[NSNotificationCenter defaultCenter] postNotificationName:#"launchProject" object:nil];
The DetailViewController inside the split view controller is listening for this notification, and switches out the views in the SVC
-(void)launchProject:(NSNotification *)notification {
Project* secondDetail2 = [[Project alloc] initWithNibName:nil bundle:nil];
ProjectRootController* secondRoot2 = [[ProjectRootController alloc] initWithNibName:nil bundle:nil ];
self.splitViewController.viewControllers =[NSArray arrayWithObjects: secondRoot2, secondDetail2 , nil];
}
I don't understand why the views aren't switching out. Any advice on this will be welcome.

You haven't shown all the code, so I'm guessing the problem is a misunderstanding of how notifications work. It can be initially confusing, but it's very straightforward. So far, you have:
[[NSNotificationCenter defaultCenter] postNotificationName:#"launchProject" object:nil]
which is fine.
But you also need to have
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(launchProject:) // selector should be your function name, launchProject
name:#"launchProject" // notification name - must be same as what is given to postNotificatioName.
object: nil];
somewhere, like in an init function.
In other words, postNotificationName:#"launchProject" does NOT call your function launchProject. It puts a notification with the name "launchProject" into the NSNotificationCenter defaultCenter. If you're not looking for that particular notification, then nothing will happen.
Hope that helps..

Related

nsnotification approach for session inactivity in objective c

In sesssion inactivity implementation for my project. I have created a NSNotification in RootViewController class of project.
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle: #"Close"
style: UIBarButtonItemStyleDone
target: self
action: #selector(closeModal)];
UIImage *image = [UIImage imageNamed:#"fidelity_logotype"];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, image.size.width, image.size.height)];
[imageView setImage:image];
[self.navigationItem setTitleView:imageView];
self.navigationController.view.backgroundColor = [UIColor fidelityGreen];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationDidTimeout:) name:#"ApplicationTimeout" object:nil];
}
- (void) applicationDidTimeout:(NSNotification *) notif
{
NSLog(#"I m here");
BCDSessionInactivityViewController *sessionView=[[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"InactivityViewController"];
sessionView.modalPresentationStyle = UIModalPresentationFormSheet;
sessionView.preferredContentSize = CGSizeMake(838,340);
[[self topViewController] presentViewController:sessionView animated:YES completion:nil];
}
and in logoutviewcontroller, i am removing this observer written below
- (IBAction)logoutbtn:(id)sender
{
NSLog(#"logout is called");
[sessionTimer invalidate];
sessionTimer = nil;
[[BCDTimeManager sharedTimerInstance]stopIdleTimer];
//[self dismissViewControllerAnimated:YES completion:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"ApplicationTimeout" object:nil];
[self performSegueWithIdentifier:#"Thankyoupage" sender:self];
}
This is code where i posting the notification.
- (void)idleTimerExceeded {
NSLog(#"idle time exceeded");
[[NSNotificationCenter defaultCenter]
postNotificationName:#"ApplicationTimeout" object:nil];
}
for first time login, it works fine whenever timer exceeds, i post a notification and model view is presesnted perfectly, but once user logs out, after that whenever the notification is posted, selector method is getting called twice
I am pretty sure that notification is getting posted only once.
Should i create notification in every view controller and then remove it when view unloads?
what i am doing wrong here?
You are adding the notification in RootViewController and trying to remove it from LogoutViewController. So that notification observer added to the RootViewController never gets removed. So each time you logout and login, the observer call will get increased by one. For fixing the issue, you need to remove the observer from the RootViewController object.
For fixing the issue you mentioned in your comment,
If I remove the observer in RootViewController , then if timers
exceeds in some other views, and notification observer is not called.
Also, i can't add observer on app delegate because we want timer
notification to be fired only after reaching rootviewController
Write two public methods in AppDelegate
One for adding observer (addObserver)
One for removing observer (removeObserver)
When you reach RootViewController, call the addObserver method for adding the observer
When logout is pressed, call the removeObserver for removing the observer

Cocoa: saveAction called 2 times with notification

I have a custom class for NSButton called MyButton where I post a notification for a quicksave
MyButton.m:
-(void)mouseDown:(id)sender{
[super mouseDown:sender];
[super mouseUp:sender];
[[NSNotificationCenter defaultCenter] postNotificationName:#"quickSave" object:nil userInfo:nil];
}
in AppDelegate I get the notification for the quick save:
AppDelegate.m:
- (IBAction)saveAction:(id)sender{
NSLog(#"Saving...");
NSError *error = nil;
if (![[self managedObjectContext] commitEditing]) {
NSLog(#"%#:%# unable to commit editing before saving", [self class], NSStringFromSelector(_cmd));
}
if (![[self managedObjectContext] save:&error]) {
[[NSApplication sharedApplication] presentError:error];
}
}
-(void)awakeFromNib{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(saveAction:) name:#"quickSave" object:nil];
}
Via the NSLog "Saving..." I see that the saveAction is called 2 times. Why?
P.S: the notification calls 2 times every function I insert in the selector: field, so maybe it has to do with the -(void)awakeFromNib{...} because I see that it's called twice (there are two different self inside the awakeFromNib).
UPDATE: I've "solved" the problem binding in Interface Builder the Application as an AppDelegate delegate and then adding the [[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(saveAction:) name:#"quickSave" object:nil]; inside the -(void)applicationDidFinishLaunching:(NSNotification *)aNotification{...}. I don't know if it's a real solution and obviously it is not an answer to my question (why awakeFromNib is called 2 times), but it might be useful to someone. Does anyone have a clue?
UPDATE2: the right managedobjectcontext is the one called in awakeFromNib the second time, the first one (identical in awakeFromNib and applicationDidFinishLaunching) is wrong.
My app is a statusbar app, the first awakeFromNib is called when i start the app and the second one when a preference window is opened.
The log message indicates that two different instances of AppDelegate receive a single notification. Probably you instantiated AppDelegate twice. Ensure you are not manually doing [[AppDelegate alloc] init] or something, and not putting more than one AppDelegate object in NIB.

Setting UIScrollView's Position from another ViewController

I am trying to set the position of a UIScrollView by using contentOffset as such:
- (void) navigateToTableViewPosition:(CGPoint)contentOffset {
NSLog(#"Position set method gets called...");
NSLog(#"%#", NSStringFromCGPoint(contentOffset));
[mainScrollView setContentOffset:contentOffset animated:YES];
}
I call this method from another view controller before I dismiss it, and everything checks out. I pass the argument correctly, and the method gets called (checked it with NSLog), but the scroll view does not move...
What is funny is that when I call this method from the view controller, in which it is located, it works fine. Only when I call it from another view controller, it stops working.
Just for future reference, here is the calling method:
MainViewController *mainView = [[MainViewController alloc] init];
[mainView navigateToTableViewPosition:contentOffset];
Content offset is a CGPoint I set beforehand. It doesn't matter here; besides, it gets passed correctly anyways.
Try this, You have to send notification from other viewcontroller when you want to change ..
[[NSNotificationCenter defaultCenter] postNotificationName:#"changepostion" object:NSStringFromCGPoint(CGPointMake(contentOffset.x, contentOffset.y))];
in mainviewcontroller
-(void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(navigateToTableViewPosition:) name:#"changepostion" object:nil];
}
- (void) navigateToTableViewPosition:(NSNotification *)notification
{
contentOffset =CGPointFromString([notification object]);
NSLog(#"Position set method gets called...");
NSLog(#"%#", NSStringFromCGPoint(contentOffset));
[mainScrollView setContentOffset:contentOffset animated:YES];
}
You can't set the properties of a view which is not visible. If you are using iOS5+ you can implement the offset setting in the completion in the view dismiss completion block.
Use delegate for backward messaging in view controllers.
Refer Basic Delegate Example link for more reference.
Your are making new instance of viewcontroller which will call method but will have no effect.

Using one ActivityIndicator with two classes

I have an UIActivityIndicator that starts animating on the top of all of my views. Right after he starts animating, the parent view of this current view is popped. Now, after he's animating, I'm calling another class with a block and runs some server commands.
My problem is, that in the other class im getting the response from the server, but I cannot tell the
UIActivityIndicator to stop, because he is in the other class. (I have to say that I don't want to implement nothing on the Application Delegate).
On the server class, after I get the response, a UIAlertView appears, but the UIAlertView is implemented inside the server class. That's where I want the UIActivityIndicator to stop.
I Hope that I understand it well, if not, please tell me.
Thank you.
- (void)buttonPressed:(id)sender
{
UIView * darkView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 480)];
darkView.backgroundColor = [UIColor blackColor];
darkView.alpha = 0.5f;
UIActivityIndicatorView * activityIndicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[darkView addSubview:activityIndicator];
activityIndicator.center = darkView.center;
[activityIndicator startAnimating];
[[UIApplication sharedApplication].keyWindow addSubview:darkView];
// Inside this class (ShareByEmail) there is a UIAlertView that should stop the
// animation that already running right now.
ShareByEmail *sbe = [[ShareByEmail alloc]init];
[sbe share];
[self.navigationController popViewControllerAnimated:YES];
}
One option is to keep the UIActivityIndicator as singleton object and use it from anywhere in the project. Another option is to try this with notifications. You need to add and remove observer to this activity indicator and whenever a request is fired/executed, you need to post a notification to start/stop activity indicator.
Update:
In your case either you can set it as [[NSNotificationCenter defaultCenter] addObserver:activityIndicator selector:#selector(startAnimating) name:#"startActivityIndicator" object:nil] and [[NSNotificationCenter defaultCenter] addObserver:activityIndicator selector:#selector(stopAnimating) name:#"stopActivityIndicator" object:nil] immediately after allocating memory for the activity indicator. Now whenever you want to start or stop it, call [[NSNotificationCenter defaultCenter] postNotificationName:#"startActivityIndicator" object:nil] or [[NSNotificationCenter defaultCenter] postNotificationName:#"stopActivityIndicator" object:nil]. Make sure that the activity indicator is not released. I would suggest you to declare your activity indicator as a class level variable in this class and allocate memory in init method or so. In your button pressed method, you can just use [darkView addSubview:activityIndicator];

manage Tableview properties from setting view controller

I have UITabBarViewController which has 2 views.
The first view has a UITableView which has 1 section and 5 rows.
The second view has a UITableView as well which has a settings options like UISwitches.
My question is how can I show and hide or remove a cell from first view by using UISwitches on the settings view? Thanks in advance.
edit
this video explain what i am trying to do (check the app view)
Press Here
you can accomplish this by using NSNotificationCenter
in your firstView you can write a code like:
-(void)viewDidLoad{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(modifyCell:) name:#"modifyCell" object:nil];
}
//make sure this is declared in your .h
-(void)modifyCell:(NSNotification*)notif
{
if (notif) {
//cellindex to modify
NSString *cellIndex = [[notif userInfo] objectForKey:#"index"];
[yourDataSource removeObjectAtIndex:[cellIndex intValue]]
[yourTableView reloadData];
}
}
in your secondView:
-(void)switchChanged
{
NSNotificationCenter *ncSubject = [NSNotificationCenter defaultCenter];
NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:#"indexNum",#"index", nil];
[ncSubject postNotificationName:#"modifyCell" object:nil userInfo:dict];
[ncSubject removeObserver:self];
}
You should reload your tableview after each UISwitch change. Such as:
- you set a delegate from your UISwitch to your UITabBarViewController (or the class which controls the events)
- you should store your tableview's cells' number in a variable
- this variable will change after each UISwitch change
- after the variable change, you should reload the tableview
In the viewWillAppear method of the table view controller I would check whether the setting has been changed or not. If it has changed then I would redraw the cell by calling its the reloadData method.
Sometimes it is recommended to call reloadData through performSelectorOnMainThread:
[ self performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO]
And your data loading methods (numberOfSectionsInTableView, numberOfRowsInSection, cellForRowAtIndexPath, etc.) will have to consider the settings value accordingly.