I have an iOS application. Application has 2 different views: Main and Settings. In fact, application needs to load and initialize some library and framework before it is used in Main View.
When I put this initialization in viewDidLoad method, it works OK. But when go to Settings and come back to Main View, initialization starts again, which is not what I want, and application results in a memory problem.
I need an method that is called once when application is started. Any idea?
EDIT: I switched to tabbed view. It loads views once. This is another solution.
You state in one of your comments that you don't want to put this code in application:didFinishLaunching and you want to keep it in viewDidLoad. You can use this snippet to run your code only the first time is is invoked:
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// code here
});
The inner block will only be executed once. If the view is loaded again, the block is not called. Note that there is an Xcode code snippet for this which you can access by starting to type dispatch_once in the editor:
Use this one:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
It should be in your appdelegate class.
Hope it helps
You can also use
+ [NSObject initialize]
Define a class method of that name, and it will be run once before any other messages are sent to that class:
+ (void)initialize {
// Put one-time initialization code here.
}
https://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/nsobject_Class/Reference/Reference.html#//apple_ref/occ/clm/NSObject/initialize
In your AppDelegate, one of the objects guaranteed to have only one instance (singleton) throughout the app, you can declare an instance variable/property:
BOOL initialized;
And then in viewDidLoad of your UIViewController, you check if it's the code has been initialized; if not, then run the code and set the variable to true:
if (!initialized) {
// Code goes here
initialized = true;
}
Related
I am trying to follow through examples from other as well as Apple. I'm lost.
I have a singleton class that I use to handle my user logging in (challenges a web server, etc.).
I want to create a block I can call, pass in the username/password. The block will perform the web service calls then return if it was successful or not.
This is what i've manage to get working so far:
My singleton class looks like this:
.h
typedef void (^AMLoginBlock)(NSString *userName, NSString *password);
#interface AuthManager : NSObject
+ (id)sharedManager;
+ (bool)loginUserWithBlock:(AMLoginBlock)block;
#end
.m
#implementation AuthManager
+ (id)sharedManager
{
static dispatch_once_t pred = 0;
__strong static id _sharedObject = nil;
dispatch_once(&pred, ^{
_sharedObject = [[self alloc] init]; // or some other init method
});
return _sharedObject;
}
+ (bool)loginUserWithBlock:(AMLoginBlock)block {
NSLog(#"im printing from AM");
return true;
}
#end
I then call the method like so:
bool rtn = [AuthManager loginUserWithBlock:^(NSString *userName, NSString *password) {
NSLog(#"im here in the block LVC.");
}];
My question is three parts:
How do I write a completion handler for the block similar to UIView animation... block.
Is it a good idea to perform these web service calls from a block based implementation?
Should I be declaring the block method like so:
- (bool)loginUserWithBlock:(AMLoginBlock)block;
instead of using +(bool)loginUser.. since it is in a singleton class. Not sure if this will cause multiple instances of the singleton to be created.
My goal is to be able to call this block like you call [UIView animation..]. So I can simply do:
[AuthManager loginUserWithUsername:foo
password:bar1
completion:^(BOOL finished) {
if (finished)
//push new view controller.
else
//spit out error
}];
Completion Handler
You will want to copy the completion block to a class iVar:
#property (nonatomic, copy) void (^completionHandler)(bool *);
Because you are saving the block, you need to have a non-class method take the block (see following for how to do this without violating your singleton). An example of your method could be:
- (void)loginUserWithUsername:(NSString *)username
password:(NSString *)password
completion:(void(^)(bool *finished))completionBlock
{
// Copy the blocks to use later
self.completionHandler = completionBlock;
// Run code
[self doOtherThings];
}
Then when your login code has finished its work, you can call the block - here I pass self.error, a bool to the block :
- (void)finishThingsUp
{
// We are done with all that hard work. Lets call the block!
self.completionHandler(self.error);
// Clean up the blocks
self.completionHandler = nil;
}
Good Idea
Well, this is a philosophical question, but I will say this: Blocks in Objective-C allow you to write code that performs a single task and easily integrate it into many programs. If you chose to not use a completion handler in your login code you would need your login code to:
Require that classes using it implement a protocol (as in a LoginDelegate)
Use some other system of informing your code such as Key Value observing or Notifications
Hard code it to only work with one type of calling class
Any of the above approaches are fine, I feel a block-based call back system is the simplest and most flexible. It allows you to just use your class without worrying about additional infrastructure (setting up notifications, conforming to protocols, etc. ) while still letting you reuse it in other classes or programs.
Singelton
Methods that begin with a + in Objective-C are class methods. You cannot use class methods to manipulate iVars, as who would own that data?
What you can do is have a class method that always returns the same instance of that class, allowing you to have an object that can own data, but avoid ever having more than one of them.
This excellent Stack Overflow answer has sample code.
Good Luck!
In a project I'm working on (I picked up this code and I've been trying to debug it), I have a function that gets called by an observer. The observer calls a method that updates data to be put on a screen. While this update is happening (it takes a few seconds for the updates to occur), a user can press the 'Back' button on the navigation bar, which causes a dealloc call to occur. While the method is running, the dealloc call releases all of the ivars, which eventually causes EXC_BAD_ACCESS when the method attempts to access the ivars. The structure of the update method is also enclosed with a #synchronized block.
- (void)update {
#synchronized(self){
// some code here...
// Also access ivars here.
}
}
What can be done to tell the controller to finish the method first before deallocating? I've tried running a while loop with a condition in the dealloc, but that doesn't seem efficient. It also never fully executes if the controller is released, and stays in a deadlock. I feel like the solution is simple, but my brain is fried from a long day at work and I can't think about it.
You can call retain on self to ensure the reference count does not reach zero while running a longer running method; and avoid the dealloc that way:
- (void) update {
[self retain]
// do work ...
[self release]
}
If you put the work you need to do in a block, the compiler will automatically retain all the objects referenced inside the block (including self). For example:
- (void)update {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// some code here, access ivars, do whatever you want
}];
}
The update method will immediately return and the block will be scheduled to run on the main run loop (no secondary threads are involved here).
If the update work is a long-running task, you can use a background queue instead of the main one, and then (inside that block) schedule another block to run on the main queue and interact with the UI when the work is done.
Since you are talking about the NavigationBar my guess is that what is happening is that your NavigationController is releasing its reference to your UIViewController class, which in turn is holding the ivars. One way around it is to retain the objects inside the viewcontroller until the calcuations are made, as the other answers suggest. However if the calculations you are doing are made to calculate what data should be shown in that view, the next time you open the same view, you will reload the view again from the beginning.
What I would do is that I would keep a reference to the ViewController that you are working with outside of the navigationcontroller, so that it does not get released when the user presses the back button.
Then later, if the user comes back to the same view, you will already have the data loaded. Just push it again using the same reference.
Example:
#interface YourRootViewController : UIViewController {
YourNextControllerClass *nextController;
}
#property (nonatomic, retain) YourNextControllerClass *nextController;
#end
In the ViewDidLoad of your top ViewController:
self.nextController = [[[YourNextControllerClass alloc] initWithNibName:#"YourNextControllerNib" bundle:nil] autorelease];
When you want to show the view:
[myNavigationController pushViewController:nextController animated:YES];
If the user presses the back button, the viewcontroller will not be released, so when you push it again, everything will be there as you left it.
The solution depends on whether you want to keep that object alive to the end of the method or not. However, you also use #synchronized (self): I would be very afraid what happens if self gets deallocated and the #synchronized tries to remove the lock on self, so in this case I would try to keep it alive. (However, #synchronised and then running lots of code is not a good idea in my opinion; #synchronised should be used for the smallest amount of code possible to avoid deadlocks).
With ARC, keeping the object alive within the method is simple.
typeof (self) myself = self;
will create a strong reference to self. And better to use myself in the method body instead of self.
If you don't want to keep the object "self" alive, which would be the usual case:
__weak typeof (self) weakSelf = self;
Then wherever you want to make sure that self is still there you write
typeof (self) strongSelf = weakSelf;
if (strongSelf != nil) {
}
For simplicity's sake, lets say I am making a stopwatch application for ios5. I have a class called stopwatch, which represents the stopwatch's state. This class possesses members that store elapsed time, whether the stopwatch is running, etc.
To me, it seems this class should be instantiated once at the beginning of my apps lifetime, thus I declare it to be a member of the AppDelegate class and instantiate it in the didFinishLaunchingWithOptions: method of the AppDelegate class
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
Stopwatch *stopwatch = [[Stopwatch alloc] init];
return YES;
}
However, I now find myself needing to be able to reference this stopwatch object in the ViewController class but not knowing how to do so.
I would greatly appreciate any advice as to how to approach this problem, as it seems to be a fundamental concept for making ios applications. Thank you!
Don’t use a singleton. There are plenty of reasons why singletons are a bad design decision in most cases, I wrote a blog post about some of them.
Don’t store arbitrary data in the app delegate. That’s just misusing an existing singleton to do what you want. The app delegate should be concerned with the app’s lifecycle events, it should not be a place to stick whatever data you want accessible from everywhere.
One possible correct approach to solve this problem is to have a class that will create you application’s object graph for you and pass the instances to all interested classes. My app delegate’s application did finish launching method mostly look like this:
- (BOOL) applicationDidFinishWhatever
{
Factory *factory = [[Factory alloc] init];
[self setWindow:[factory buildMainWindow]];
[window makeKeyAndSomething];
return YES;
}
And all the object creation and assembly gets done in the Factory class. The Factory will create the timer (and keep the single instance in memory, if needed) and it will pass the timer to view controllers:
- (void) buildMainWindow
{
UIWindow *window = …;
[window setRootViewController:[self buildMainController]];
return window;
}
- (void) buildMainController
{
UIViewController *controller = …;
[controller setTimer:[self buildTimer]];
return controller;
}
I have created a sample Xcode project that shows how to wire an app without singletons. It’s very simple right now, I will add some common use cases later.
You can use Singleton pattern. look here for more info What should my Objective-C singleton look like?
If you "declare it to be a member of the AppDelegate class" then you should use it as a property:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions {
Stopwatch *aStopwatch = [[Stopwatch alloc] init];
self.stopwatch = aStopwatch;
[aStopwatch release];
...
}
Later, anywhere in your code:
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate doSomethingWithStopwatchMethod];
someVariable = appDelegate.stopwatch.timeSinceStart;
...
Another approach would be to use a singleton (check SO for dozens of questions on the subject) or even a plain global variable (an integer holding a flag for instance) declared in main.m.
Could someone please explain how control of execution flows in an iOS application? I know that UIApplicationMain is called first from main. Then what? What is the relationship between my defined methods and main? Is it all event-driven or can there be some structured sequence?
I don't mean to be so vague, I just need to know where to start. Perhaps I'm looking at this in the wrong way.
For example, in C++ I would do something like:
#include "myMethods.h"
int main (int argc, char * const argv[]) {
Method1(); // Initialization
Method2(); // Opening views and options
Method3(); // Meat of the program
return 0;
}
Thanks in advance.
So, as you mentioned, the main() function in main.m is the starting point, which then calls UIApplicationMain(). If you check the docs, you'll see that UIApplicationMain takes four arguments:
argc,
*argv[],
*principalClassName
*delegateClassName.
The first two of those are just the argument count and variable list passed from main(). But the third and fourth arguments are pointers to NSStrings. The third argument specifies which class should be UIApplication. Unless you intend on subclassing UIApplication, you specify nil for the third argument. The fourth argument specifies which class should be UIApplication's delegate class, which will respond to anything specified in the UIApplicationDelegate Protocol. You don't have to muck with this directly, as it's included in all of the Xcode templates:
int main(int argc, char *argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
Don't let the NSStringFromClass([AppDelegate class])) bit throw you. That's just a fancy way of specifying the fourth argument so that the right delegate gets called should you later change the name of AppDelegate.m.
UIApplication starts the main event loop and calls -application:didFinishLaunchingWithOptions:, one of the methods its delegate has to handle. Take a look at AppDelegate.m, and you'll find some template code for this method. This is where you can start customizing, creating things that need to be in place before the UIWindow and other instances of UIView get created:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
So, now the application window and root view controller are defined, and the app is off and running.
All of this, and quite a bit more, is excellently explained here: http://oleb.net/blog/2012/02/app-launch-sequence-ios-revisited/
As you said UIApplicationMain creates an application execution in the system. Among the stuff the application loading process does, I assume you are interested in what is relevant to a specific application. Also I assume a typical case, which is illustrated in many project templates that Xcode provides.
The application loading process looks into the application's information property list. There it finds 'Main nib file base name', and the UIApplication instance of your application loads the corresponding nib file from the application bundle. This nib file specifies an application delegate class, and tells to connect an instance of the class to the delegate property of your UIApplication instance.
Depending on the main nib file, other objects may be created and connected as well, for example, the application's window, the main view controller, etc.
Now the loading sequence ends, and everything is all event-driven, starting from your application delegate class to get the famous -applicationDidFinishLaunching: message.
From Apple Documents -
The application life cycle constitutes the sequence of events that occurs between the launch and termination of your application. In iOS, the user launches your application by tapping its icon on the Home screen. Shortly after the tap occurs, the system displays some transitional graphics and proceeds to launch your application by calling its main function. From this point on, the bulk of the initialization work is handed over to UIKit, which loads the application’s main nib file and readies the event loop.
Application Life Cycle
I got this code:
GrooveOnDownload *dlg = [[GrooveOnDownload alloc] init];
NSURLDownload *dw = [[NSURLDownload alloc] initWithRequest:request delegate:dlg];
It starts the download in a delegate class with outlets for UI controls. But for some reason controls don't respond to direct messages from the delegate.
//Header of the delegate
#interface GrooveOnDownload : NSObject {
IBOutlet id downloadButton;
//...
//Implementation
//...
[downloadButton setEnabled:FALSE]; // Doesn't work
//...
Any ideas?
It is my fourth day of Mac development so I don't know much about the platform.
Edit : 2010-05-28 01:03:41.486 GrooveOnLite[3303:a0f] Download button = (null)
Edit 2 :
Edit 3 :
I miss Windows .....
Edit 4
In Win32 you send one window message to the button. Everything is handled by WndProc loop. It is damn simple. In Mac you have this magical interface builder which somehow gets all that crap working. The delegate gets called by some withcraft magic. The rest of the classes are connected by some 'magical' force. In windows there is an tmain function which is the entry point. That's it! No retarded outlets and such shit.
I know it sounds obvious, but is everything connected correctly in Interface Builder?
Edit
If the download is on a separate thread, then fbrereto is correct and you'll need to perform the selector on the main thread. Your code would need to be changed to look like this:
[downloadButton performSelectorOnMainThread:#selector(setEnabled:)
withObject:[NSNumber numberWithBool:NO]
waitUntilDone:YES];
A few notes: in Objective-C the keyword NO is used instead of FALSE. It's a primitive type, so in order to use it here we had to box it in a NSNumber object. The waitUntilDone argument does exactly what you would expect, and you can change that to NO if you'd rather not wait.
Edit 2
Here's a more complete code example about how to accomplish what I think you want, which is to reuse a single instance of GrooveOnDownload from your app delegate. I'm assuming that your app delegate class is called GrooveOnLiteAppDelegate.
// GrooveOnLiteAppDelegate.h
#interface GrooveOnLiteAppDelegate : NSObject
{
IBOutlet GrooveOnDownload *grooveOnDownload;
// other properties go here
}
// your method signatures go here
#end
// GrooveOnLiteAppDelegate.m
#implementation GrooveOnLiteAppDelegate
- (void)mySuperAwesomeMethod
{
// it's up to you to figure out what method to put this in and
// how to call it
NSURLDownload *dw = [[NSURLDownload alloc] initWithRequest:request delegate:grooveOnDownload];
}
#end
Given that code in your app delegate, you'll have an outlet in IB that you can connect to your GrooveOnDownload object in IB. If you do that, then grooveOnDownload will be a pointer to that object.
All UI calls have to be made on the main thread; if the download is happening in the background your delegate may be getting notified on a thread other than the main one, in which case a call to a UI element would have to be done through something like -[NSObject performSelectorOnMainThread:withObject:waitUntilDone:modes: or another related API.