Swift: AnyClass is not a type - swift

I'm trying to access an application delegate from SDK that does not know the class name of the application delegate. I mean that my SDK doesn't know what class will be an application delegate in a basic project. So I find a class that conforms to the protocol UIApplicationDelegate.
let numberOfClasses: UnsafeMutablePointer<UInt32> = UnsafeMutablePointer<UInt32>.alloc(0)
let classes = objc_copyClassList(numberOfClasses)
var appDelegateClass: AnyClass? = nil
for i in 0...Int(numberOfClasses.memory) {
if class_conformsToProtocol(classes[i], UIApplicationDelegate.self) {
appDelegateClass = classes[i]
}
}
But the result has "type" "AnyClass?". The following code results getting an error "'applicationDelegateClass' is not a type":
if let applicationDelegateClass = appDelegateClass {
if let delegate = UIApplication.sharedApplication().delegate as? applicationDelegateClass.self { }
}
How could I solve it?

I actually shouldn't use the specific application delegate class. The right code:
if let delegate = UIApplication.sharedApplication().delegate! as? UIApplicationDelegate {}

Related

In swift , how to implement a variable in the app delegate, in order to retrieve it everywhere in the app?

In swift, how to create a variable in the app delegate in order to retrieve it everywhere in the app?
I am not talking about NSManagedObject
I know that it begin with :
let appDelegate = UIApplication.shared.delegate as! AppDelegate
I have a class Personne
class Personne {
var One: String
var Two: Float
}
and another classe to create a Singleton:
class PersonneController {
var shared = Personne()
and in my app, i have created an instance like this:
var personne = Personne()
so every variable is retrieving by
personne.shared.myvariable
How to put personne in the app delegate, in order to retrieve it from everywhere?
1 . Create the instance of your "Personne" Class in AppDelegate
( var persnee = Personne())
2 . create a function in your AppDelegate to which will return instance of AppDelegate
class func appDelegate() -> AppDelegate
{
return UIApplication.shared.delegate as! AppDelegate
}
3 . You can call like this
AppDelegate.appDelegate(). persnee
Inside the class
class AppDelegate..... {
var name:String?
}
Then
let appDelegate = UIApplication.shared.delegate as! AppDelegate
print(appDelegate.name)
But for this it's better to make a singleton class like
class Service {
static let shared = Service()
var name:String?
}
Then
print(Service.shared.name)
or even make it a global variable
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let aVariable = appDelegate.blabla

WatchKit App Get's Nil when initializing class

I am trying to update my app to utilize SwiftUI architecture. It is a stand alone WatchKit app. I used to pass a few key classes between views utilizing the delegate approach. Since I am trying to utilize environmentObject, I would like to initialize the initial classes (which depend on each other) via the delegate.
Given I am using SwiftUI method, I have recreated AppDelegate in the #main.
import SwiftUI
class AppDelegate: NSObject, WKExtensionDelegate {
var class1: Class1?
var class2: Class2! = Class2()
var class3: Class3!
func application(_ application: WKExtension) -> Bool {
return true
}
}
#main
struct WatchApp: App {
#WKExtensionDelegateAdaptor(AppDelegate.self) var delegate
init() {
delegate.class1 = Class1()
delegate.class2 = Class2()
delegate.class3 = Class3()
}
#SceneBuilder var body: some Scene {
WindowGroup {
NavigationView {
ContentView()
.environmentObject(delegate.class3)
.environmentObject(delegate.class2)
.environmentObject(delegate.class1)
}
}
WKNotificationScene(controller: NotificationController.self, category: "myCategory")
}
}
When Class 3 get's called I get a nil value in the access of the AppDelegate and a crash.
#if os(macOS)
let delegate = NSApplication.shared.delegate as! AppDelegate
#elseif !os(watchOS)
let delegate = UIApplication.shared.delegate as! AppDelegate
#else
let delegate = WKExtension.shared().delegate as! AppDelegate //<HERE's The Crash - Thread 1:EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
#endif
}
And in the info.plist
<key>WKExtensionDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).AppDelegate</string>
Is there an obvious thing I am overlooking?
WKExtension.shared() is always defined, but delegate property may be nil. Using as! is what crashes your app
You will have to provide a delegate to handle lifecycle events in your extension, see Apple Doc
To assign an AppDelegate for the extension, follow this steps:
Create a class with name YOUR_CLASS_ExtensionDelegate that implements the protocol WKExtensionDelegate.
Make sure the value of WKExtensionDelegateClassName in Info.plist in WatchKit Extension is $(PRODUCT_MODULE_NAME).YOUR_CLASS_ExtensionDelegate
In your case, you already did 1, but you should check for 2

Why do I need to force the type using this Swift generic function?

I had some repetitive UIViewController boiler-plate scattered around that I wanted to encapsulate, so I defined this generic UIViewController extension method:
extension UIViewController {
func instantiateChildViewController<T: UIViewController>(
storyboardName: String? = nil,
identifier: String? = nil
) -> T {
let storyboard: UIStoryboard!
if let name = storyboardName {
storyboard = UIStoryboard(name: name, bundle: nil)
}
else {
storyboard = UIStoryboard(name: "\(T.self)", bundle: nil)
}
let vc: T!
if let identifier = identifier {
vc = storyboard.instantiateViewController(withIdentifier: identifier) as! T
}
else {
vc = storyboard.instantiateInitialViewController()! as! T
}
self.addChildViewController(vc)
self.view.addSubview(vc.view)
return vc
}
}
However, when I use this extension like so:
class ChildViewController: UIViewController { /*...*/ }
class ParentViewController: UIViewController {
private var childVC: ChildViewController!
//...
func setupSomeStuff() {
self.childVC = self.instantiateChildViewController() //<-- Compiler error
let vc: ChildViewController = self.instantiateChildViewController() //<-- Compiles!
self.childVC = vc
}
}
I get the compiler error Cannot assign value of UIViewController to type ChildViewController! on the line with the comment above. However, if I use an intermediate variable that I explicitly give a type to it works.
Is this a Swift bug? (Xcode 8.1) My interpretation of how generics work is that in this case T should equal the more specific ChildViewController, not the less constrained UIViewController. I get the same issue if I defined childVC as private var childVC: ChildViewController?, the only work-around I've found is the local variable, which obviously makes the extension less compelling, or to do an explicit cast like:
self.childVC = self.instantiateChildViewController() as ChildViewController
I've seen this too. I think there's some weird behavior around Optionals the compiler isn't dealing with as expected.
If you change the return value of the function to an optional value it should work without a problem.
func instantiateChildViewController<T: UIViewController>(//whateverParams) -> T!
or
func instantiateChildViewController<T: UIViewController>(//whateverParams) -> T?
Also, your childVC should be a var rather than a let if you're going to set it anyplace other than an initializer

Get variable value or run function from different Object - Swift

I am trying to: get the value of a few variables, as well as run some functions which live in Object A, all from Object B.
I have tried for hours now to make it work with delegates and protocols. No luck.
I can't do something like this:
var delegate: MyDelegate = ViewController()
Because it seems to create a new instance of ViewController. And I want the values from the instance that is already running.
I also cannot do:
var delegate: MyDelegate?
Because the ViewController object never responds. So I get a nil anytime I call delegate?.somefunction()
I don't want a segue between screens. I just need to start a function from another object.
I bet this is an easy fix. I just can't get it. Thanks for your help.
Some of my code:
class PauseButtonView: NSView{
var delegate: PauseButtonDelegate?
...
var result = delegate?.startFunction()
}
protocol PauseButtonDelegate {
func startFunction() -> String
}
class ViewController: NSViewController, PauseButtonDelegate {
func startFunction() -> String {
let myString = "Hello World!"
return myString
}
}
If you don't want either classes to have a reference to the other, you could use internal notifications to communicate between them:
// in your PauseButtonView
let object:[String:AnyObject] = [ "aParameter" : 42 ]
let startNotification = NSNotification(name: "startFunction:", object: object)
NSNotificationCenter.defaultCenter().postNotification(startNotification)
// in the view controller
func startFunction(notification:NSNotification)
{
let object = notification.object as? [String:AnyObject]
//...
}

How do I get a reference to the AppDelegate in Swift?

How do I get a reference to AppDelegate in Swift?
Ultimately, I want to use the reference to access the managed object context.
The other solution is correct in that it will get you a reference to the application's delegate, but this will not allow you to access any methods or variables added by your subclass of UIApplication, like your managed object context. To resolve this, simply downcast to "AppDelegate" or what ever your UIApplication subclass happens to be called. In Swift 3, 4 & 5, this is done as follows:
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let aVariable = appDelegate.someVariable
Swift 4.2
In Swift, easy to access in your VC's
extension UIViewController {
var appDelegate: AppDelegate {
return UIApplication.shared.delegate as! AppDelegate
}
}
Convenience Constructors
Add in AppDelegate Class at the end of code
Swift 5.7
func appDelegate() -> AppDelegate {
return UIApplication.shared.delegate as! AppDelegate
}
To use AppDelegate reference anywhere in code?
For example: Call AppDelegate Method named setRoot
appDelegate().setRoot()
This could be used for OS X
let appDelegate = NSApplication.sharedApplication().delegate as AppDelegate
var managedObjectContext = appDelegate.managedObjectContext?
It's pretty much the same as in Objective-C
let del = UIApplication.sharedApplication().delegate
Here is the Swift 5 version:
let delegate = UIApplication.shared.delegate as? AppDelegate
And to access the managed object context:
if let delegate = UIApplication.shared.delegate as? AppDelegate {
let moc = delegate.managedObjectContext
// your code here
}
or, using guard:
guard let delegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let moc = delegate.managedObjectContext
// your code here
Appart from what is told here, in my case I missed import UIKit:
import UIKit
SWIFT < 3
Create a method in AppDelegate Class for ex
func sharedInstance() -> AppDelegate{
return UIApplication.sharedApplication().delegate as! AppDelegate
}
and call it some where else for ex
let appDelegate : AppDelegate = AppDelegate().sharedInstance()
SWIFT >= 3.0
func sharedInstance() -> AppDelegate{
return UIApplication.shared.delegate as! AppDelegate
}
Try simply this:
Swift 4
// Call the method
(UIApplication.shared.delegate as? AppDelegate)?.whateverWillOccur()
where in your AppDelegate:
// MARK: - Whatever
func whateverWillOccur() {
// Your code here.
}
Here's an extension for UIApplicationDelegate that avoids hardcoding the AppDelegate class name:
extension UIApplicationDelegate {
static var shared: Self {
return UIApplication.shared.delegate! as! Self
}
}
// use like this:
let appDelegate = MyAppDelegate.shared // will be of type MyAppDelegate
Make sure you import UIKit
let appDelegate = UIApplication.sharedApplication().delegate! as! AppDelegate
it is very simple
App delegate instance
let app = UIApplication.shared.delegate as! AppDelegate
you can call a method with one line syntax
app.callingMethod()
you can access a variable with this code
app.yourVariable = "Assigning a value"
extension AppDelegate {
// MARK: - App Delegate Ref
class func delegate() -> AppDelegate {
return UIApplication.shared.delegate as! AppDelegate
}
}
In my case, I was missing import UIKit on top of my NSManagedObject subclass.
After importing it, I could remove that error as UIApplication is the part of UIKit
Hope it helps others !!!
I use this in Swift 2.3.
1.in AppDelegate class
static let sharedInstance: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
2.Call AppDelegate with
let appDelegate = AppDelegate.sharedInstance
In Swift 3.0 you can get the appdelegate reference by
let appDelegate = UIApplication.shared.delegate as! AppDelegate
As of iOS 12.2 and Swift 5.0, AppDelegate is not a recognized symbol. UIApplicationDelegate is. Any answers referring to AppDelegate are therefore no longer correct. The following answer is correct and avoids force-unwrapping, which some developers consider a code smell:
import UIKit
extension UIViewController {
var appDelegate: UIApplicationDelegate {
guard let appDelegate = UIApplication.shared.delegate else {
fatalError("Could not determine appDelegate.")
}
return appDelegate
}
}
In the Xcode 6.2, this also works
let appDelegate = UIApplication.sharedApplication().delegate! as AppDelegate
let aVariable = appDelegate.someVariable