how to use AppDelegate Function in ViewController in macos application - ios

I am a rookie ios developper . I am confused about how to use a function that I have defined in Application. here my Code
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ notification: Notification) {
}
// I try to use this function in my View's Button
func test() {
print("test")
}
}
I also have use this code in my View
let appDelegate = NSApp.delegate as! AppDelegate
appDelegate.test()
but I have error say
could not cast value of type 'SwiftUI.AppDelegate' (0x7fff8a2c6110) to 'learnSwift.AppDelegate'
thanks all you answer my question

Related

React Native: save a value send to a Native Module on AppDelegate

I'm building a Native Module in Swift for a RN app where I "remove" the RN view and load a Storyboard, everything works fine but I need to send a value from RN to this Module but it is not being saved, I think it's because the controller is loaded again after a call it so the value is lost
This is a simplified version of my code, I call the openMyModule function on the RN side with the value and it should save the value on a variable, then it calls a function on AppDelegate that will open the Storyboard
#objc (MyModule) class MyModule : UIViewController {
#objc static func requiresMainQueueSetup() -> Bool { return true }
var value = ""
#objc func openMyModule(_ rn_value: String) -> Void {
self.value = rn_value
DispatchQueue.main.async {
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
appDelegate.goToNativeView()
}
}
}
}
This is the function of AppDelegate
- (void) goToNativeView
{
UIViewController *vc = [UIStoryboard storyboardWithName:#"MyModuleScreen" bundle:nil].instantiateInitialViewController;
self.window.rootViewController = vc;
[self.window makeKeyAndVisible];
}
I think that when I call goToNativeView my controller is loaded again, that's why the value is lost
So, what I need is the value to still being available on my controller or save the value on AppDelegate and call it when I need it
There is any way I can achive this?
If anyone else face this problem, here is how I solved:
I created another Swift file to save this value and made the variable static
class AnotherClass {
static var value = ""
}
Then, when I just set the value when I receive it
#objc (MyModule) class MyModule : UIViewController {
#objc static func requiresMainQueueSetup() -> Bool { return true }
#objc func openMyModule(_ rn_value: String) -> Void {
AnotherClass.value = rn_value
DispatchQueue.main.async {
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
appDelegate.goToNativeView()
}
}
}
}
and now it works!

Unable to call method of ViewController()

I am simply trying to make a method in the ViewController class and be able to call it.
Here is my code (I note the 2 ways I tried calling it, and the errors I got):
import UIKit
class ViewController: UIViewController{
func sayHi(name: String){
print("Hi \(name)")
}
}
/*
let viewcontroller = ViewController()
viewcontroller.sayHi(name: "Bob")
*/
//Error: Expressions are not allowed at the top level
/*
ViewController.sayHi(name: "Bob")
*/
//Error: Expressions are not allowed at the top level
//Error: Instance member 'sayHi' cannot be used on type 'ViewController'; did you mean to use a value of this type instead?
So as you can see in the commenting, I tried to call sayHi as a type method and as an instance method. Neither worked. I will ultimately create a function that can take input from a text input, and manipulate it. Is ViewController.swift even the right file to be doing this? If so, how do I call a method that I have defined?
There will be this delegate in appDelegate which will be called when you app is launched. Create your viewController there and add it to the window.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
let viewController = ViewController()
window?.rootViewController = viewController
viewController.sayHi()
return true
}
This will work on Playground, but not on Xcode.
Xcode's code is compiled and then you have an app. The first point where a call happens is AppDelegate and from there your first controller and its methods are initialised. Nothing outside a class will be executed.
Use playground for tests or any other online swift playground.
If you want to run sayHi immediately, put it in viewDidLoad and load the app. Delete all further code outside of the class before building again:
override func viewDidLoad() {
super.viewDidLoad()
sayHi()
}
You can create a instance of controller inside a function or a block
when you are working in a class or Xcode projects in Xcode Playground your way of accessing the function sayHi(name: String) in
ViewController works.
For Xcode projects try the following
import UIKit
class ViewController: UIViewController{
func sayHi(name: String){
print("Hi \(name)")
}
}
class SecondViewController: UIViewController{
override func viewDidLoad() {
super.viewDidLoad()
let viewcontroller = ViewController()
viewcontroller.sayHi(name: "Bob")
}
}
When you initialise the SecondViewController you can access the ViewController()
To execute the function sayHi(name: String) immediately when the
ViewController() is initialised you can call it in viewDidLoad() or in
func viewWillAppear()
import UIKit
class ViewController: UIViewController{
override func viewDidLoad(_ animated: Bool) {
super.viewDidLoad(animated)
//Call the function hear
sayHi(name: "Bob")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// or call hear
sayHi(name: "Bob")
}
func sayHi(name: String){
print("Hi \(name)")
}
}

Class protocols not working after updating from Swift 2.3 to Swift 3.0

I have a very basic user class, who os responsible for get user data from Firebase and update the currently screen if needed, everything was working until a decided to update my project to Swift 3.0
This is the User Class
#objc protocol userClassProtocol {
func updateScreen()
#objc optional func sucessUnlockedCategory()
}
class User {
static let sharedInstance = User()
internal var delegate : userClassProtocol?
func fakeClassThatGetsDataFromFirebase() {
//Got data
print("Has new data")
self.delegate?.updateScreen()
}
}
And here is the ViewController:
class FirstViewController: UIViewController, userClassProtocol {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("View will load")
User.sharedInstance.delegate = self
}
func updateScreen() {
print("Screen is going to update")
//Do stuff here
}
}
The logs i get from this are:
Has new Data
View Will Appear
But the function updateScreen() in the view controller never gets called. No errors are being pointed out by Xcode.
Looks like it's just an issue with the timing of your method calls.
Your fakeClassThatGetsDataFromFirebase method is called first, and at that point, your delegate hasn't been set. So self.delegate is nil when calling:
self.delegate?.updateScreen()
This will only work if your viewWillAppear gets called before fakeClassThatGetsDataFromFirebase
It shouldn't get called, according to your code. Nothing calls fakeClassThatGetsDataFromFirebase(), which is what should call updateScreen() on your delegate method.

Transform UIApplicationDelegate methods into RxSwift Observables

In RxSwift / RxCocoa you can create a reactive wrapper for a delegate (e.g. UIScrollViewDelegate or CLLocationManagerDelegate) to enable Rx observable sequences for certain delegate methods.
I am trying to implement this for the UIApplicationDelegate method applicationDidBecomeActive:
What I tried so far is pretty straightforward and similar to the DelegateProxy subclasses that are included in RxCocoa.
I created my DelegateProxy subclass:
class RxUIApplicationDelegateProxy: DelegateProxy, UIApplicationDelegate, DelegateProxyType {
static func currentDelegateFor(object: AnyObject) -> AnyObject? {
let application: UIApplication = object as! UIApplication
return application.delegate
}
static func setCurrentDelegate(delegate: AnyObject?, toObject object: AnyObject) {
let application: UIApplication = object as! UIApplication
application.delegate = delegate as? UIApplicationDelegate
}
}
And an Rx extension for UIApplication:
extension UIApplication {
public var rx_delegate: DelegateProxy {
return proxyForObject(RxUIApplicationDelegateProxy.self, self)
}
public var rx_applicationDidBecomeActive: Observable<Void> {
return rx_delegate.observe("applicationDidBecomeActive:")
.map { _ in
return
}
}
}
In my AppDelegate I subscribe to the observable:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// the usual setup
// and then:
application.rx_applicationDidBecomeActive
.subscribeNext { _ in
print("Active!")
}
.addDisposableTo(disposeBag)
return true
}
When I start my app "Active!" gets printed and then I get the following crash in RxCocoa's _RXDelegateProxy_ class:
Does anybody have an idea what the problem might be? Or has anybody successfully implemented something like rx_applicationDidBecomeActive?
It looks like a really tricky issue with RxSwift and memory management.
The default implementation of DelegateProxyType sets an instance of a delegate proxy (in this case, RxUIApplicationDelegateProxy) to the delegate of UIApplication.
It also stores the original AppDelegate as a property called forwardToDelegate so all the delegate methods can still be passed to it.
The problem is that, when the new app delegate is set:
application.delegate = delegate as? UIApplicationDelegate
the original one is deallocated! You can check it by overriding deinit in AppDelegate. The reasons are explained in this answer. And because the property forwardToDelegate is of type assign, your app crashes as the property points to a deallocated object.
I have found a workaround for that. I'm not really sure if it is a recommended way, so be warned. You can override a method from DelegateProxyType in RxUIApplicationDelegateProxy:
override func setForwardToDelegate(delegate: AnyObject?, retainDelegate: Bool) {
super.setForwardToDelegate(delegate, retainDelegate: true)
}
In normal circumstances, you don't want to retain the delegate as it leads to a retain cycle. But in this special case, this is not a problem: your UIApplication object will exist the entire time while your application is alive anyway.

Swift Passing data from appDelegate to another class

I need to pass a variable from the AppDelegate to another class that I have created to hold global variables of the project and I'm not able to find a way to make it work.
This is the code in the AppDelegate:
func application(application: UIApplication!, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData!) {
println("Device's token is: \(deviceToken)")
//Global Variables Class Instance
let globals:Globals = Globals()
globals.setDeviceToken("test1") //method1 not working
globals.deviceToken = "test2" //method2 not working
}
This is my Globals Class:
public class Globals {
var deviceToken = String()
init() {
//nothing
}
func setDeviceToken(s:String){
deviceToken = s
}
func getDeviceToken() -> String {
return deviceToken
}
}
If i try to print the value, from other files of the project, I'm not able to get anything, just an empty string.
class ViewController: UIViewController {
//Global Variables Class Instance
let globals:Globals = Globals()
override func viewDidLoad() {
println(globals.getDeviceToken()) //return empty string
println(globals.deviceToken) //return empty string
There are several patterns you can use to achieve what you want
You could access the AppDelegate through the UIApplication:
let delegate = UIApplication.sharedApplication().delegate as AppDelegate
let deviceToken = delegate.deviceToken
Look into singletons. A quick google search for 'Swift singleton' will get you a long way. The first result:
class SingletonB {
class var sharedInstance : SingletonB {
struct Static {
static let instance : SingletonB = SingletonB()
}
return Static.instance
}
}
Then use sharedInstance to instantiate the singleton anywhere and access the same variables.
The first one is quick and dirty, so for more serious projects I would recommend the singleton pattern.
There are probably a million ways to do this, but this should get you started
(More at this link, which explores a few ways to implement singletons: https://github.com/hpique/SwiftSingleton )
I simply solved my problem using NSUserDefaults
in the AppDelegate:
NSUserDefaults.standardUserDefaults().setObject(deviceToken, forKey: "deviceToken")
NSUserDefaults.standardUserDefaults().synchronize()
From other classes:
NSUserDefaults.standardUserDefaults().objectForKey("deviceToken")
Honestly I don't know if this is a good way to do it but it's working

Resources