How do I implement delegate methods through Swift extension - ios

My project is a mix of Obj-C and Swift, and I'm trying to extend my AppDelegate class with Swift.
So right now I have AppDelegate.m, AppDelegate.h, and AppDelegate.swift. Most of the methods are in the Obj-C file, but I'm trying to implement just one of the methods:
extension AppDelegate {
func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]?) -> Void) -> Bool {
}
}
However it's complaining:
AppDelegate.swift:11:10: Method 'application(_:continueUserActivity:restorationHandler:)' with Objective-C selector 'application:continueUserActivity:restorationHandler:' conflicts with previous declaration with the same Objective-C selector
Is this a limitation of Swift extension? Or is there a way to implement this delegate method in my Swift extension file?

You cannot do something like that. AppDelegate has defined this method (UIApplicationDelegate protocol says so).
The simplest solution would be to rewriteAppDelegate in swift.
You have also more difficult solution - remove UIApplicationDelegate from your AppDelegate and implement this protocol in your extension. It may raise unexpected errors if your AppDelegate is considerable size.

Related

SwiftUI 2 accessing AppDelegate

I did a small prototype which uses Firebase Cloud Messaging and the new SwiftUI 2 app life cycle. I added a custom AppDelegate via
#UIApplicationDelegateAdaptor(AppDelegate.self) var delegate and disabled method swizzeling for FCM to work. Everything is working as expected.
Today a colleague asked me, if one can get that delegate object via UIApplication.shared.delegate. So I gave it a shot and noticed that there seems to be two different AppDelegate objects:
po delegate prints:
<MyProject.AppDelegate: 0x6000009183c0>
where as po UIApplication.shared.delegate prints:
▿ Optional<UIApplicationDelegate>
▿ some : <SwiftUI.AppDelegate: 0x600000b58ca0>
Now I'm wondering what is the correct way of accessing the AppDelegate? Should one get it via an #EnvironmentalObject and pass it along all views? Or use the old fashioned way via UIApplication?
Additionally I would like to understand why I end up with two AppDelegates.
Your MyProject.AppDelegate is not direct UIApplicationDelegate, it is transferred via adapter to internal private SwiftUI.AppDelegate, which is real UIApplicationDelegate and which propagates some delegate callback to your instance.
So the solution might be:
Use #EnvironmentalObject if you need access to your MyProject.AppDelegate only in SwiftUI view hierarchy (for this AppDelegate must be confirmed to ObservableObject).
Add and use MyProject.AppDelegate static property which is initialized with object created via adapter, like
class AppDelegate: NSObject, UIApplicationDelegate {
static private(set) var instance: AppDelegate! = nil
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
AppDelegate.instance = self // << here !!
return true
}
}
now everywhere in your code you can access your delegate via AppDelegate.instance.

Where the AppDelegate get set as a delegate for the application?

Environment, Swift 5.3 and Xcode 12
Normally we do someObject.delegate = self to set the current class as the delegate for some class instance. However, inside AppDelegate there is no such assignment to make it a delegate of the application.
import Cocoa
#main
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {}
func applicationWillTerminate(_ aNotification: Notification) {}
}
So where the application's delegate property get set?
#UIApplicationMain attribute means that this class is the application delegate, https://docs.swift.org/swift-book/ReferenceManual/Attributes.html#ID589.
It's the same as calling the UIApplicationMain(:,:,:,:). If the attribute is NOT used, supply a main.swift file with code at the top level that calls UIApplicationMain(:,:,:,:) (also applicable to NSApplication).
Adding #main seems to have the same effect as #UIApplicationMain. Replace #main with #UIApplicationMain and the app works just fine, tested.

Cannot find connected accessory if EAAccessoryManager.shared() is called in AppDelegate constructor

If I call EAAccessoryManager.shared() inside the AppDelegate constructor e.g.
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var accessoryManager = EAAccessoryManager.shared()
...
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
return true
}
...
}
Then later I access the accessory manager to get connected accessories (with an accessory connected) EAAccessoryManager.shared().connectedAccessories.count returns 0, which is incorrect.
If I don't call EAAccessoryManager.shared() in the AppDelegate constructor, then EAAccessoryManager.shared().connectedAccessories.count returns 1, which is correct.
I can workaround this problem, but I really wanted to understand why this might be happening, as I could have misunderstood something about how the EAAccessoryManager is meant to work (or perhaps something more fundamental about how an app is initialised - I am new to iOS programming).
Has anyone hit this problem before, or maybe have an idea why this could be happening?

performSelector error with global function and AppDelegate class

I'm following this apple document and I'm trying to translate some of its parts in Swift language. I have this global function, with performSelector:
func RunLoopSourceScheduleRoutine(info:UnsafeMutableRawPointer? ,rl:CFRunLoop? , mode:CFRunLoopMode?) {
let obj : RunLoopSource = Unmanaged<RunLoopSource>.fromOpaque(info!).takeUnretainedValue()
let del = UIApplication.shared
let theContext = RunLoopContext(withSource: obj, andLoop: rl!)
del.performSelector(onMainThread:#selector(AppDelegate.registerSource) , with: theContext, waitUntilDone: false)
}
And AppDelegate class, in this class there are: methods that automatically adds Xcode in the normal routine of project creation (didFinishLaunchingWithOptions, applicationWillResignActive, etc) I added the sourcesToPing parameter and the registerSource() method:
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var sourcesToPing : [RunLoopContext] = Array()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
func registerSource(sourceInfo:RunLoopContext) {
sourcesToPing.append(sourceInfo)
}
}
but the compiler get the following error , in RunLoopSourceScheduleRoutine() function:
argument '#selector' refers to instance method 'registerSources(source Info:)' that is not exposed to Objective-C
what is the problem ? and how does it solve?
PerformSelector is an Objective-C method that predates GCD (Grand Central Dispatch). It should be possible to do it that way, but selectors are not type-safe and are awkward to use.
I'm not sure what's wrong with your current code. As Martin points out in his comment, the error you're reporting is complaining about a method called registerSources() but you show code for a method called registerSource() (with no final "e".) If you want to get that code working you need to get to the bottom of that discrepency.
Instead, why not use GCD code like this:
dispatchQueue.main.async() {
registerSource(theContext)
}
That will accomplish the same goal but using the more modern GCD

Could not cast value of type 'LLAppDelegateProxy'

I have integrated the Localtyics iOS SDK. After this I am getting the error like below:
Could not cast value of type 'LLAppDelegateProxy'
It means I am unable to get a reference of the App delegate object. I am in trouble now because I want Localytics & want a reference object of App delegate as well.
Does any body know a solution of this?
Localytics replaces your AppDelegate behind-the-scenes with their proxy class
(LLAppDelegateProxy). Localytics suggests creating a static reference to your original AppDelegate for access like so:
class AppDelegate: UIResponder, UIApplicationDelegate {
static var originalAppDelegate: AppDelegate!
// ...
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
AppDelegate.originalAppDelegate = self
// ...
}
Access using:
AppDelegate.originalAppDelegate.someMethod()

Resources