I need some advice about best practice of developing iOS app design
Here's what I'm dealing with: when iOS device looses internet connection (or doesn't have one and figuring that out) I want my app to go to some sort of offline mode, i.e. firing some event, sending some NSNotifications, m.b. showing some sort of alert etc. Accordingly, when iOS device gets it's connection back I want the oposite thing - move my app to some sort of online mode.
So, what I want is to have ability to access app's mode (i.e. to check whether app is online or offline) from within some of my ViewControllers. I'm thinking of two methods of storing app's state:
1) Have some AppDelegate's property and access it from anywhere via my AppDelegate. AFAIK, that's a wrong approach, because AppDelegate is not supposed to be used as global object for application, but for doing launch initialization and controlling application's state changes.
2) Store this information on Model level. But I have no idea what am I supposed to use on Model level for such purpose. I don't think using Core Data or NSUserDefaults is a good idea, because I don't want this property to be persistent, I need it only during current application running. And apart from Core Data and NSUserDefaults I don't actually know any other Model level techniques.
I don't include any code examples, because it's mostly a theoretical question.
you can use singleton pattern and store the variable as a property
for example
#interface GlobalData : NSObject
#property BOOL connectionAvailable;
+ (GlobalData *)sharedInstance;
#end
#implementation
+ (GlobalData *)sharedInstance {
static GlobalData *sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[GlobalData alloc] init];
});
return sharedInstance;
}
#end
// --- in some method
[GlobalData sharedInstance].connectionAvailable = /* connection state */;
// --- in some other method
BOOL connectionAvailable = [GlobalData sharedInstance].connectionAvailable;
The second approach works best. You surely don't need any persistence a property indicating the internet connection. A good thing to do is having your Model be a singleton class, that exposes a readonly BOOL property for the internet connection and your view controllers can subscribe to its changes via key-value observing. Your model can also implement internally the Reachability class for updating the internet connection status.
I'm assuming you're using Apple's Reachability class. http://developer.apple.com/library/ios/#samplecode/Reachability/Introduction/Intro.html
I created a category on the Reachability class to add a sharedInstance singleton that allows you to check the state of the internet connection. I use this in all my apps.
Here's how you do singletons:
How do I implement an Objective-C singleton that is compatible with ARC?
Related
I've been thinking about using a singleton on my data class in my current app. I've also been thinking of reasons not to use the pattern and currently I am stuck in the middle.
The reason I am for the singleton in this case is due to accessibility to methods and properties easily that I need to use more than once throughout the app. I could use the appDelegate for this but that muddles up the area of concern as these methods / variables have nothing to do with the app state - more to do with user input. The data will be persisted with eventually with NSUserDefaults - which is a singleton already.
The reason I am against it is because its another singleton to an app that already bass one (The appDelegate)
My question:
Would using another Singleton to access the data model be the correct way / acceptable way of doing it - or should I look at another approach?
I personally think there would be nothing wrong with a singleton as a data model - using the app delegate to instantiate it when the app starts and then access its various methods / properties when I need them throughout the app. This would be the only other singleton in the app (Maybe another one for user management - e.g.; logging in / out / profile / credentials, etc? )
Any thoughts?
Thanks all!
There is no problem having multiple singleton classes within ios, in fact in many of my projects most of the classes are singletons. Normally I have the data access logic and control within a singleton and then actual object classes as instances.
As you have already identified you really do not want to be putting something into AppDelegate that does not apply to the whole app.
From my point of view do not instanciate the class from AppDelegate, simply have the class instanciate itself on first access.
Whenever I am explaining singleton Objective-C to people I always direct them to this site, it may be worth a view for you:
http://www.galloway.me.uk/tutorials/singleton-classes/
It explains only what you need in a really easy to understand way. The bit that does the 'self-instanciating' is this bit:
+ (id)sharedManager {
static MyManager *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
You could use singleton in these case. Don't use delegate to hold values for your app. You may use same singleton for user management also.
Note : Don't use globals unless you need to do so. Singletons and top-level data should be used only when the data they contain truly belongs at the top level.
I have designed a login app. I have entered the account data in sqlite database. However when I logged in with the account username and password i want these to be accessible to all view controllers. Because, I have different controllers which will update the account details. Need implementation details..
Thanks
Use a singleton: http://www.galloway.me.uk/tutorials/singleton-classes/
I have a project with something like this (note I'm using the iOS keychain rather than a database, but I've hidden those details here):
#interface User : NSObject
#property (nonatomic, strong) NSString *username;
+ (User *)currentUser;
#end
#implementation User
+ (User *)currentUser
{
static User *currentUser = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
currentUser = [[User alloc] initFromKeychain];
});
return currentUser;
}
#end
There are A LOT of approaches to doing singletons (depending on how paranoid you want to be about whether someone can create a non-singleton instance of your class or not). Examples here: What should my Objective-C singleton look like?
You could also just access the keychain directly wherever you need it. You should also ask yourself why so much of your code needs access to a username/password. Sounds like a broken design.
Avoid global
variables, rather you can use a Singleton class to store application wide credentials information.
However keep in mind that the best way to store credentials in an app is using Apple Keychain, you can find the API reference on the Apple site.
As it was said - avoid global variables, but if you want them for sure - do it like in c language:
define this variable in one file
in all other files refer to it with extern keyword
Simply: Don't do it!
I recommend to store the credentials in the keychain. But don't use the sample code Apple provides. It doesn't work. I use SSKeychain in my projects.
If you don't need to store the credentials you should, as aleroot suggested, use a singleton or a class with only one instance.
Three answers:
Don't do it.
If you must do it, use a Singleton.
For extremely easy access to username and non confidential (i.e., password) variables, use NSUserDefaults.
I've got a test project to use the private data object on several view controller.
(I've downloaded it from web & git-hub)
- (ExampleAppDataObject*) theAppDataObject;
{
id<AppDelegateProtocol> theDelegate = (id<AppDelegateProtocol>) [UIApplication sharedApplication].delegate;
ExampleAppDataObject* theDataObject;
theDataObject = (ExampleAppDataObject*) theDelegate.theAppDataObject;
return theDataObject;
}
First question is, theDelegate was casted with AppDelegateProtocol, even this applications UIApplication delegate name was ViewControllerDataSharingAppDelegate, and there's no warning. I can't under stand why, maybe it's because that was a id type?
(AppDelegateProtocol is a custom delegate protocol he declared in the AppDelegate.)
Second, it shows this kind of code on every view controller, and it seems like just a single-ton pattern.
I don't think this is not the best way to transfer data between view controller.
Which is the best way to transfer object data type?
Thanks.
Creating a protocol decouples the code somewhat from the specific implementation. You could conceivably have several applications, each of which uses its own custom class as an app delegate, but all implementations conform to the AppDelegateProtocol.
I used to use the app delegate to hold global data and methods a lot when I first started in iOS.
However, that fills your app delegate with app-specific code.
I've shifted away from that approach recently, and use a data container singleton (and perhaps a utility methods singleton as well.) As is typical for a singleton, I define a class method that lets me fetch the singleton. I add properties to my singleton as needed to store data, and then just use the class method to get a pointer to the singleton. I write my class method to lazy load the singleton.
Its also easy to make your data container singleton persistent by making it conform to NSCoding. Then every time you get moved to the background, just save your singleton somewhere. On app launch, read it in.
I have a Web API class which handles all network communication and downloads in my project. My project contains both collection views and tableviews which are updated whenever a download is complete.
My way to handle this feels ugly.
I pass references to my collection views/table views to the methods in WepAPI.m.
Whenever a download is complete I use the references to insert new objects to my views and to send reload messages.
Is this the way to go? Should I use KVO or some other method instead?
I am using AFNetworking Framework to handle my web communication
I'd use blocks.
For example: (in WebAPI.h)
typedef void (^SomeStuffBlock)(id someStuff);
- (void)getSomeStuffWithCompletion: (SomeStuffBlock)completion;
Use a singleton so that the downloader stays in memory. (Put this in your WebAPI.m)
+ (id)sharedInstance {
static dispatch_once_t once;
static id sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
Calling would be like this:
[[WebAPI sharedInstance] getSomeStuffWithCompletion: ^ (id someStuff) {
//Make changes to your views here
}
This ensures that the view changes you make are done in their corresponding view controllers.
an easy pattern should be to use two singletons:
a ConnectionManager, which handles auth, timeout, parsing,
a DataManager, which asks the ConnectionManager to fetch the endpoints and store the parsed results.
Then you can use KVO (or NSNotifications) to listen to any updates to your DataManager singleton.
This way of doing things is simple enough and provides a fair amount of reusability for each of the components involved.
Im doing a small test project with SocketRocket on ios. But i can't seem to wrap my head around the logic.
Here's the thing: I have need to have a sort of "global" function to call the sockets. When my app opens it should connect using the websockets.
_webSocket.delegate = nil;
[_webSocket close];
_webSocket = [[SRWebSocket alloc] initWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"ws://localhost:12345/connectr"]]];
_webSocket.delegate = self;
self.title = #"Opening Connection...";
[_webSocket open];
However, i need to get the logic on connecting to a delegate function. I already thought of a singleton but i read that the singleton functions are quite cpu expensive.
So basically my question is:
What is the best way to initiate a global accesable function that uses the (appdelegate) initalized SocketRocket instance.
You can use a singleton without trouble. Really. It's way better than making your AppDelegate with 50000 LOC. Also, your AppDelegate should know only about app events, not sockets.
I don't know how you assume singletons are cpu expensive. The only expense of singleton is lazily initialising the object once in the first call.
In the other hand, singleton pattern is usually considered a bad practice because of accessing an object statically because you are referring the singleton class instead of a reference to the instance. But it's certainly better to use a singleton instead of accessing the app delegate.
you declare variable in appdelegate with property and synthesis
you import appdelegate class in your requirement class
AppDelegate *objappdel=(AppDelegate*)[[UIApplication sharedApplication]delegate];
objappdel.variablename;