I have created a drop down banner system, like GameKits (When you get an achievement for example).
I can easily display the banner in one view with the code below. However, all my server code is stored in a singleton class, and would like to notify the user when something happens in there (regardless what view controller they are in). How would I go about doing this?
[self displayBannerWithTitle: #"title here"];
Thanks in advance
Related
I have been all over stackoverflow and all over Google and I cannot seem to figure this one out. Here's my scenario:
I have my app's "main screen" where the user first makes decisions about what they're going to do. The app works off of a CoreData database which is created by "importing" XML files. The user can choose to open an XML file attached to an email in my application, which automatically triggers my main screen to show up and run the import of the file.
I can get this far without any issues. In my storyboard, I have a segue called ParseSegue from my main screen to a view controller which will handle the parsing and give the user some status information.
When the main screen is called via the email app, the main screen automatically calls
[self performSegueWithIdentifier:#"ParseSegue" sender:self];
I then check for this segue name in prepareForSegue and it's a valid name. This is where I assign the file URL to the parser controller so that it can parse the correct file.
The problem is that the segue never actually happens. The prepareForSegue method gets called, the name "ParseSegue" can be checked against and is valid, but the segue itself simply does not happen. If I add a button to the main screen and tell it to perform the segue within the storyboard, it works fine. But calling it programmatically seems to do nothing.
It turns out that I was looking in the wrong place entirely. My problem was that in my appDelegate, where the app reacts to the incoming URL, I was inadvertently creating a new instance of my storyboard and my main view controller. This was different than the one which was already active and may or may not have been on the screen.
The controller I was creating was never actually shown. I only noticed this because the log:
NSLog(#"Source: %#", [segue.sourceViewController description]);
would show different memory addresses for my test (the button push) and the import test. This led me to believe that I was, in fact, working with two different instances of the storyboard and the app's main view controller. Thanks to Paul for the suggestion of logging the destination and the source controllers.
So I posted a question a while back which can be seen at: How to reset an iOS application when a user clicks the "sign out button"?
Following the advice I made a sign out button where a user where by is taken to the main screen where they can register or sign in again. What I am finding out is that when a new user signs in, I am seeing certain value from the old user in pickers, UITextView ETC
Is there a way to reset application state or do I have to go the long route of making sure that each outlet is set to default values? Is this a sign of bad programming practice somewhere?
The Cocoa way = KVO (key value observing). Controllers interested in being informed about login state change register themselves as observers on login component/controller/whatever instance does the login.
After login/logout this component notifies all observers about state change. Those then do all necessary actions: populating UI with user data after log in or resetting them after log out.
Very flexible pattern that avoids unnecessary dependencies between components.
Ok first thing you have to do is make your main view implement the delegate for signout successful. In this you got to reset all the data and views which will be recreated/repopulated when a new user signs in.
Inorder to achieve this you can analyse your code/logic as to what is created on a new user sign in and reset all these in the delegate method for sign out. This is way to generic an answer but resetting the data is the way to do it.
Alternatively you can recreate your main view when sign in is successful i.e. remove the main view and on sign in success create it afresh for the new user.
The cleanest way would be to create a new set of view controllers and set them to the viewControllers of the UITabBarController object but it needn't be the cheapest always. This will be something that you need to check if it's viable or not.
Otherwise, you'll have to to consider adding reset methods to the view controllers. If the tab is a navigation controller, popToRootViewControllerAnimated: and reset the first view controller. This one is a bit of effort to implement compared to the former approach.
When ever you go to new controller just allocate the whole controller again. and dont forget to release once the navigation is done.
Heres the sample code example to do it
-(void)goToFormController
{
FormViewController *objFormViewController = [[FormViewController alloc]initWithNibName:#"FormViewController" bundle:nil];
[self.navigationController pushViewController:objFormViewController animated:YES];
[objFormViewController release];
}
Happy iCoding...
I have an app with a navigation controller as the root view. There are many views that can be pushed in.
The user has to create an account to use the app. The user can then log into this account from other devices, but only one device can be logged onto the same account at a time. So if multiple devices try to log into an account, only the latest device will be logged in and the other devices are logged off (a push is sent to the devices).
Since there are multiple views that the device could be showing before it was logged off, I call popToRootViewControllerAnimated: to get back to the root view. This is because when the user logs in the next time I only want the root view to be shown (the new account might not have access to the previously shown view).
If the user has an alert view or action sheet presented (which uses the current view as its delegate) before the push is received, the view will still be shown after the popToRootViewControllerAnimate: method is called. If the user then taps on a button for the alert view or action sheet, it will send a message to the dealloc'd view and crash the app.
An example:
myViewController is being shown to the user.
myViewController create an action sheet prompting the user for a decision.
The push is received for the device to log out.
The navigation controller pops all the views controllers and now shows myRootViewController.
Since the view controllers are popped, myViewController is now dealloc'd.
The action sheet from myViewController is still shown.
When the user selects an option form the action sheet, a message is sent to myViewController, and since it is already dealloc'd, a crash will occur.
Is there any way to prevent this?
One solution I have considered would be to keep track of all the objects that uses a specific view controller as its delegate. Then when that view controller dealloc's it will also set all the object's delegates to nil. This requires me to manually take care of every view controller when they create an object that uses itself as the delegate, since I cannot think of a way to automatically create and update this list.
Any better solution (or improvement to mine) would be appreciated!
Edit: The alert view and action sheet are only examples of some objects that I would use myViewController as a delegate. I am also using a number of other classes (and third-party libraries) that implements this delegate pattern.
A few ideas:
you can encapsulate the alert/action sheet view and delegate in a single class. Then when you need an alert view, create MyAlertView instead, which will also be its own delegate and will do [self release] after the user taps a button.
make your App Delegate the only delegate for all your alert views and action sheets. App Delegate is always around while the application is running, so there won't be a problem with a released delegate.
The problem with both solutions is that if you need your application to know what happened in the alert view/action sheet, you somehow need to tell the interested class of the user's choice.
You can do that by either using delegates of your own - which would mean you're back to square one - or use notifications: when the alert view/action sheet delegate is called, it would post a notification ([[NSNotificationCenter defaultCenter] postNotificationName:NotificationName object:self userInfo:userInfo];), while the interested object would look for that notification ([[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(onNotification:) name:NotificationName object:nil];) and perform whatever tasks necessary in onNotification:(NSNotification*)aNotification method.
You'll be able to agree with yourself on what type of information is passed in those notifications (I would think the button number in a NSNumber class would be enough, or perhaps pass the button text, too). And you won't have to keep track of all alert views - just don't forget to remove the observer ([[NSNotificationCenter defaultCenter] removeObserver:self name:postNotificationName object:nil];) in the views' dealloc.
Edit:
"This requires me to manually take care of every view controller when they create an object that uses itself as the delegate, since I cannot think of a way to automatically create and update this list."
Actually you probably can do this in a semi-automated way: make a singleton object with a method like
-(id)delegate:(id)delegate for:(id)forWhom
And then instead of
someThingy.delegate = self;
you'd do
someThingy.delegate = [[DelegateLocker defaultLocker] delegate:self for:someThingy];
Inside the DelegateLocker you'd have a MutableDictionary with delegate class as a key and a MutableArray of someThingies as a value. Then in your view controllers' deallocs you'd call
[[DelegateLocker defaultLocker] delegateIsDying:self];
which would go through the thingies and assign delegate = nil for each
The drawback of course is that you'll be retaining all the thingies for an indefinite period of time instead of releasing them immediately.
So the ViewController that presented the action sheet iand set itself as the delegate right? So why dont you keep a reference to the ActionSheet in the ViewController, in the dealloc method of the view controller, you can check if the action sheet is visible, if it is then set the delegate of the action sheet to nil,and dismiss it...
so
-(void)dealloc
{
if(myActionSheet && [myActionSheet visible])
{
[myActionSheet setDelegate: nil];
//dismiss
}
}
Hope that helps
If you want automated solution, I think you can make a function to iterate through Ivars of your view controller to see if any Ivar has delegate property and set it to nil.
k, I'm new to this so apologies all around, generally.
I'm trying to access the UISwitch value (on or off) from a different view and class and can't make it work.
It's a simple 2 view app. Main view and the second is a preference menu.
trying to write an if/else method to play sound when the switch (on the other view) is on and not when its off.
I cant seem to make it work. Any thoughts or some syntax examples would really help me out.
Thanks.
As Matt Wilding said "it's not good form to access UI components of one view controller from another...".
Instead of accessing the view object, when the switch state is changed by the user you save the status into NSUserDefaults as preference value. Whenever you want, you can access the switch status value through the preferences.
I'm going to take what I think you're trying to accomplish here and suggest an alternative approach. You want to have a preference in your app (assumed from "preferences menu") that allows the user to set something like whether or not you app plays background music. (May not be exact, this is just for clarification).
Typically, in a well designed app, the flow is driven by the data, with the UI reflecting the state of the data model and the controllers coordinating the two layers. What you are suggesting is to have your application play music based on the state of the UI, which is not backed by any data model. This cuts out the model level, and as you noticed, can lead to awkward attempts at communicating between the UI of different controllers for information.
Things like application preferences are typically stored in a nifty .plist file that is managed through the NSUserDefaults class. This would be a great place for the data level tracking of your preference. In this situation, the UISwitch would represent the state of the flag in the settings file, and changing the value of the switch would change the value in the file. Anywhere else in your application that you need to know if the play-sound-flag is set, you reference the data model info instead of the UI. This decouples the view controllers from each other, which is a good thing.
For this purpose add selector for swith and make NSInteger property in app delegate.Like the followed
[
yourSwitch addTarget:self action:#selector(switched:) forControlEvents:UIControlEventValueChanged];
-(IBAction) switched: (id)sender
{
int state=0;
if(yourSwitch.on)
state=1;
else
state=0;
objAppDelegate.switchState=state;
}
then you need to access this appDelegate property in second view where you are playing sound
then according to this value you can do what you want and for making object of appDelegate class you need this line
YourAppDelegateClass *objAppDelegate=(YourAppDelegateClass *)[[UIApplication sharedApplication] delegate];
ok if you have any other doubt then you can ask.
I have a tableview based app that downloads rss feeds from the web. So i have view1, i click a row in the table and the results show on view2. This works great but if i change back to view1 while the data is being downloaded. It crashes!
Any ideas what i need to change (its nsxmlparser by the way)?
Thanks
Some more information about the problem would be useful to understand what's going on, but based on what you posted my guess would be that you are setting a delegate for something (the NSXMLParser or the url connection, or maybe something else) and when you go back to view1, view2 gets destroyed, destroying the delegate object and leaving whoever it was with a dangling delegate pointer.