0

I am trying to transfer a variable containing an array from my app delegate to a class that I call DataSource. But I am having trouble transferring the data. When I looked and tried to debug my app, it showed that the variable in my class, DataSource has no value while the variable from my app Delegate had values. Here is my code, can anyone help me out? [also, this I used swiftui in this app]

AppDelegate:

import UIKit
import CoreData
import Moya
import Alamofire
import AlamofireImage

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

let service = MoyaProvider<YelpService.BusinessProvider>()
   let jsonDecoder = JSONDecoder()
var theViewModels = [RestrauntListViewModel]()

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.



    loadBusinesses()


    return true
}


private func loadBusinesses () {
                    service.request(.search(lat: 34.0016, long: -117.8176)) { (result) in
                        switch result{
                        case.success(let response):
                            print("yaya")
                            let root = try? self.jsonDecoder.decode(Root.self, from: response.data)
                            let viewModels = root?.businesses.compactMap(RestrauntListViewModel.init)
                            let dataSource = DataSource()
                            dataSource.arrayOfImages.removeAll()
                            for image in viewModels! {

                                Alamofire.request(image.imageURL).responseImage { response in
                                    if let image = response.result.value {
                                        print("image downloaded appdelegate")
                                        dataSource.arrayOfImages.append(image)
                                        print(dataSource.arrayOfImages)
                                    } else {
                                        print("ERROR: image does not = response.result.value")
                                    }
                                }
                            }

                            self.theViewModels = (root?.businesses.compactMap(RestrauntListViewModel.init))!
                            print("the constant theViewModels in the appdelegate has \(self.theViewModels.count) values")

                        case .failure(let error):
                            print("Error: \(error)")
                        }
    }
}

DataSource:

class DataSource {
    let appDelegate = AppDelegate()
    var arrayOfImages = [UIImage(named: "placeholder")]

}
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • 1
    You create a DataSource instance in loadBusinesses(), which is only captured by your image download requests. Once all the image downloads are completed, that instance goes out of scope and is deleted, because you're not storing that instance anywhere. – Peter Parker Feb 26 '20 at 23:17
  • how would I be able to store that instance, peter? –  Feb 26 '20 at 23:40
  • You can have your data source be a property of app delegate. That way you can access it from other parts of your app. – Wattholm Feb 27 '20 at 00:06

2 Answers2

0

Here's a minimal example that explains my comment:

class AppDelegate: UIResponder, UIApplicationDelegate {

    var arrayOfData = [Int]()

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.

        arrayOfData.append(1)
        arrayOfData.append(2)
        arrayOfData.append(3)

        return true
    }

Then in your VC you can access your array by getting a reference to the app delegate:

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Get the data from app delegate
        let appDelegate = UIApplication.shared.delegate as? AppDelegate
        print(appDelegate?.arrayOfData)
    }

}

In your specific code, you can move this line where you create the data source:

let dataSource = DataSource()

to be just above where you declare your view models (theViewModels), so that you can reference it from elsewhere, just as I did with arrayOfData.

You may also want to make your property private and access it with a getter, to adhere to conventional programming practice.

More examples can be found here, although the accepted answer is meant for Objective-C:

Passing Data from App delegate to View Controller

Scroll down and you will see other ways to do what you need, even passing data back and forth between the App Delegate and other VCs.

Wattholm
  • 849
  • 1
  • 4
  • 8
0

Here's an example of storing a bearer token in App Delegate and using it in any other class. Below is the code for AppDelegate class :

import android.app.Application
import android.content.Context
import android.content.SharedPreferences

class AppDelegate : Application() {

    companion object {
        private const val PREFS_NAME = "MyPrefs"
        private const val KEY_BEARER_TOKEN = "bearerToken"

        private lateinit var instance: AppDelegate

        fun getInstance(): AppDelegate {
            return instance
        }
    }

    private lateinit var sharedPreferences: SharedPreferences

    var bearerToken: String? = null
        private set

    override fun onCreate() {
        super.onCreate()
        instance = this

        sharedPreferences = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)

        bearerToken = sharedPreferences.getString(KEY_BEARER_TOKEN, null)
    }

    fun saveBearerToken(token: String) {
        bearerToken = token

        val editor = sharedPreferences.edit()
        editor.putString(KEY_BEARER_TOKEN, token)
        editor.apply()
    }
}

And add this line in the android manifest tag:

android:name=".AppDelegate"

Now to save the token, one can use the following code in the Activity :

val token = "tokenString"
AppDelegate.getInstance().saveBearerToken(token)

Try to use the above code before the setContentView in the application's starter activity

Now, to use this data in any other class, you can use :

AppDelegate.getInstance().bearerToken