When using SwiftUI's #UIApplicationDelegateAdaptor, many in the Swift community(SO, blogs, courses) register the app delegate class like this:
#UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
Apple's documentation uses code similar to this example:
#UIApplicationDelegateAdaptor var appDelegate: AppDelegate
I've been using the latter with no problems that I've noticed. The latter seems more readable. Could someone explain the difference and when I should use one over the other? I think I'm not understanding something.
The fully specified version would be:
#UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate: AppDelegate
Since both types (variable type and propertyWrapper type) are the same, you can omit either of them and it will be inferred.
Related
I have application wide config variables such as mixpanel token, twillio access token, etc. that currently I am storing as global constants in my AppDelegate. Is there a better to put thesee?
// TODO: Is there a better place to put these?
let appId = 1.....2
let contactUsPhoneNumber = +17.......2
let mixpanelToken = "1..............2"
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
...
}
Some options I have considered:
Global Variables — This seems like actually the best approach; super easy, quick, etc.
"Configs" Class — Slightly more organized than #1
Info.plist — Using XML, reading/writing it in Swift is a nightmare.
Another.plist — Same as #3, but at least the configs are now stored separately from Apple's
Config.json — Will have less of the XML nightmares, but still will need to read/write a file, which is annoying.
Anything else I am missing?
Ideally keep these values in some class or struct that makes sense to own them. If there really is no such thing, then at least namespace them by declaring them as static let instance properties of an enum or struct. Do not let them "float free" as in your example code.
I'm using an API that recommends keeping its client in the app delegate and accessing it through there. If I extended UIViewController to make it easier to access the app delegate, is this any way an antipattern?
extension UIViewController {
var appDelegate: AppDelegate {
return UIApplication.shared.delegate as! AppDelegate
}
}
class SomeViewController: UIViewController {
...
appDelegate.someClient.someMethod()
...
}
By antipattern I mean that is it overkill to extend the entire UIViewController class for this simple convenience? Are there any negative impacts, overall, of extending classes like this? Does every view controller, even if it doesn't access the API, implicitly point to the app delegate now?
If I extended UIViewController to make it easier to access the app
delegate, is this any way an antipattern?
extension UIViewController {
var appDelegate: AppDelegate {
return UIApplication.shared.delegate as! AppDelegate
}
}
No; quite the contrary. It is quite common to need to access the app delegate and cast it to its actual class so as to be able to access a property or call a method in the app delegate. If this might need to be done in multiple places, a computed property is the standard notation for providing a shorthand. (There is no need to use an extension for this purpose, but there's no harm in doing so, and there may be a notational advantage; for example, the extension can be located in the app delegate file.)
In a comment, you muse about the wisdom of extending UIViewController. I imagine you have, say, two view controllers that need to access the app delegate, and many others that do not.
Now, in the first place, that doesn't really change my answer. I can't see what harm it would do or how it is in any way an antipattern to give all your view controllers the ability to access the app delegate via a shortcut even if many of them never actually do so. All view controllers have the ability already to do lots of things that most of them will never actually do.
But let's say you feel otherwise. Then you could just implement appDelegate explicitly in each relevant view controller (at the cost of violating DRY).
Or (here's the cool part) you could declare a protocol and a protocol extension, and have only the relevant view controllers adopt it. So, here's your AppDelegate.swift file:
import UIKit
protocol AppDelegateAccesser {}
extension AppDelegateAccesser {
var appDelegate: AppDelegate {
return UIApplication.shared.delegate as! AppDelegate
}
}
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
// ....
}
Now let's say that only the MyViewController class actually needs to access the app delegate. Then you just say
extension MyViewController : AppDelegateAccesser {}
This injects appDelegate into MyViewController but no other class. So you would just do that for each view controller that needs to access the app delegate, and no others. I think that's a totally unnecessary exercise, as opposed to your original proposed solution, but it does solve the problem of injecting code only into some classes.
NOTE: In Swift 5 it will be legal to declare that only a UIViewController subclass may adopt this protocol. You might like that.
Put this function to AppDelegate file so you can access AppDelegate throughout your project.
class func shared() -> AppDelegate {
return UIApplication.shared.delegate as! AppDelegate
}
You can use like :
AppDelegate.shared()
Right now, I'm trying to use a class from Git called Insomnia to prevent the device from locking while it is charging. The project is here if you're curious. For the example code, it has me doing this:
final class AppDelegate: UIResponder, UIApplicationDelegate {
private let insomnia = Insomnia(mode: .whenCharging)
//app delegate code
}
As you can see, it has you declare the AppDelegate as final so that the insomnia variable isn't deallocated, which would stop it from working. However, I wasn't sure, is this bad practice to declare my AppDelegate as final? Or will this cause issues for my app? If it is bad practice, is there a better way of making sure insomnia isn't deallocated?
You say:
As you can see, it has you declare the AppDelegate as final so that the insomnia variable isn't deallocated ...
That’s not what final does. It merely says that the class cannot be subclassed (which is not likely to ever be relevant in the case of an app delegate). The final keyword also permits some optimizations (where if you had code calling any of these methods, it could use static dispatch instead of dynamic dispatch) that are unlikely to have any observable effect in this scenario.
Bottom line, you do not have to use final in this context.
"Best practice" would be to use final where you need to, namely where the class really cannot or should not be subclassed or where you really need the performance difference that static dispatch offers.
In answer to your question whether this is an acceptable place to declare insomnia, yes it is (but no final needed). The AppDelegate is not released while the app is running and it's where we generally put "app lifecycle" related code.
I'm currently working on a product that needs to swizzle the AppDelegate's application:didReceiveRemoteNotification: (I don't want to call my new method in the appDelegate itself).
The thing is: the swizzling simply doesn't work. I've already swizzled methods several times before with success, and this time, the replacing implementation is simply not called. I was wondering if that was because of some specificity of the appDelegate's methods, since these are called by the system, and not the application.
I am going to assume most of the things which are missing in your question, Its a great idea to always post the questions with code samples whenever possible.
You need to make sure that you are swizzling your methods on the specific implementation of UIApplicationDelegate and NOT the UIApplicationDelegate itself. For Eg
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#end
In this case you need to swizzle the AppDelegate Class.
Also, if you are trying to write a static library/framework you may not know the name of this class at all. In such cases simplest/safest way is to ask for App's AppDelegate name and use that to retrieve a specific class instance via NSClassFromString() or you can just brute force to find the class you need (because you usually have a Single AppDelegate class).
unsigned int numberOfClasses = 0;
Class *classes = objc_copyClassList(&numberOfClasses);
Class appDelegateClass = nil;
for (unsigned int i = 0; i < numberOfClasses; ++i) {
if (class_conformsToProtocol(classes[i], #protocol(UIApplicationDelegate))) {
appDelegateClass = classes[i];
}
}
EDIT
There are a few shortcomings of the above approach,
It iterates over all the classes accessible by your application code, looping through all of these classes is not a performant solution.
Many famous SDKs will swizzle or dynamically extend your AppDelegate, because a lot of interesting things can be intercepted at this single place. This also means that your application may have more than one implementation of UIApplicationDelegate protocol and the code above may just pick any implementation of it, causing some serious issues.
As, Chris suggested in comments below, its much safer and performant to just use [[UIApplication sharedApplication].delegate class]. which should give you the exact AppDelegate implementation known to iOS application at the moment of calling this line of code.
I know this could be a noob question but I am a bit stucked here. I usualy makes the following to access app data in different ViewControllers: First I declare a global.h module like this
global.h
typedef struct {
NSString *appName
NSString *appVersion;
bool mode;
} structApp;
extern structApp app;
After that I declare in MainViewController.h the struct so that I can access data
#implementation ViewController
structApp app;
- (void)viewDidLoad
{
app.appVersion = #"v1.02";
}
#end
And then I include "global.h" in every ViewController.h
This way I can access globally. As far I can see this is a good implementation and I have used it in more than 20 apps. Problem starts when this struct grows in size. In those cases I see corrupted memory, nil variables that were previously loaded with data, etc.
There is a better way of making data available in all ViewController? Please give me some examples if you can.
You have two options
Use a singleton class - Refer Objective C Singleton
Declare properties in App delegate - Refer SO
You can access the app delegate from any class using:
AppDelegate *appDel = [[UIApplication sharedApplication] delegate];
As you were using extern in your structure, any object updating the same value.
In OOPS, global variables are never said Good, so you need to use a singleton pattern.
Create a singleton/shared class having all those stuffs in your structure and use it.
You should deal with struct only if you deal with primitive data (if you are in a OOP way).
app.appVersion = #"v1.02";
Make your struct pointing on dangling pointer, since you are pointing a data in a function scope (app.appVersion is only holding the pointer, not the data). So you must retain all those object values in order to make it content safe, but i must admit it is still a Q&D approach.
If you need global access to data, you can use a singleton, only if you really need strong encapsulation and control to data.
How to make a singleton
What should my Objective-C singleton look like?
You can use macro too, that way you'll can use constants string without worrying data persistency, since they will always be available into the scope you are dealing with.
If you only want to read the data and you dont need any complex data structure you can also use a settings file like
Settings.h
#define appName #"blabla"
#define appVersion #"1.01"
#define mode 1
In General using struct should work fine. There is nothing wrong with using them. If you observe weird values caused by overlapping memory or illegal re-use of it or so then your problem is somewhere else but not in using structs in principle. The extern statement could lead to such an issue.
A class is not much more than a struct too, from a memory usage perspective. If I were you I would design a class with properties where ever you have members when using a struct. And make use of them in pretty the same way.
For "global variables" I apply a singleton pattern. That is basically a class with a class method (the leading + instead of -) that makes the one and only instance of the class available. Within that method I check if the class (a class internal static reference to the same class) is already available (!= nil) and instantiate it. Sometimes I use the initialize method for that. Initialize is an objective-c typical thing. It is called only once for each class, even subclassed ones, when or before the class is used for the first time. A very good place for instantiating class variables as singletons but not portable to other programming languages.