Search code examples
swiftinstance-variablescompletionhandler

In a Swift Class how do I use a @Published instance member within a property initializer


I am trying to use a completion handler in a view model that assigns values to @Published variables. I get an error stating I cannot use instance members within the property initializer. I tried adding these variables to the class init with no success. If someone could point me in the right direction it would be appreciated. Below is the view model.

class VOOViewModel: ObservableObject {
    @Published var isloading: Bool
    @Published var vooValues1: [TradingDayPrices]
    var vooTempValues1: [TradingDayPrices] = []
    let dataContainer: NSPersistentContainer
    var vooCompactDataString: String = ""
    var vooCompactDataArray: [IndexFund] = []
    var vooContainerEmpty: Bool = false
    var updatedVOODataAvailable: Bool = false
    var latestVOOArrayDate: Date = Date()
    var latestVOOContainerDate: Date = Date()
    var vooFullDataString: String = ""
    var vooFullDataArray: [IndexFund] = []
    init() {
        isloading = true
        vooValues1 = []
        dataContainer = NSPersistentContainer(name: "Index Funds")
        dataContainer.loadPersistentStores { description, error in
            if let error = error {
                print("Core Data Failed to Load: \(error.localizedDescription)")
            }  // end if let
        }  // end load persistent stores
        SetupVOO(using: vooCompletionHandler)
    } // end init
    let vooCompletionHandler: ([TradingDayPrices], Bool) -> Void = { prices, loadingComplete in
        DispatchQueue.main.async {
            vooValues1 = prices
// Error = Cannot use instance member 'vooValues1' within property initializer; property initializers run before 'self' is available
            isloading = loadingComplete
// Error = Cannot use instance member 'isloading' within property initializer; property initializers run before 'self' is available
        }
    }
    func SetupVOO(using completionHandler: ([TradingDayPrices], Bool) -> Void) {
        Task(priority: .userInitiated) {
            do {
                vooCompactDataString = try await GetOnlineDataAA(urlString: URLStrings.VOOCompact)
                vooCompactDataArray = await ConvertStringToArrayAA(stringData: vooCompactDataString)
                let vooContainerEmpty = await IsDataContainerEmptyAA(moc: dataContainer.viewContext, fundName: "VOO")
                if vooContainerEmpty == true {
                    updatedVOODataAvailable = true
                } else {
                    latestVOOArrayDate = await GetLatestArrayDateAA(dataArray: vooCompactDataArray)
                    latestVOOContainerDate = await GetLatestContainerDateAA(moc: dataContainer.viewContext, fundName: "VOO")
                    if latestVOOArrayDate > latestVOOContainerDate {
                        updatedVOODataAvailable = true
                        await DeleteContainerDataAA(moc: dataContainer.viewContext, fundName: "VOO")
                    } // end if
                } // end else
                if updatedVOODataAvailable == true {
                    vooFullDataString = try await GetOnlineDataAA(urlString: URLStrings.VOOFull)
                    vooFullDataArray = await ConvertStringToArrayAA(stringData: vooFullDataString)
                    await UpdatePersistentStoreAA(moc: dataContainer.viewContext, fundName: "VOO", dataArray: vooFullDataArray)
                    await NormalizeDatesAA(moc: dataContainer.viewContext, numYears: 1, latestDate: latestVOOArrayDate, fundName: "VOO")
                    await NormalizeDatesAA(moc: dataContainer.viewContext, numYears: 5, latestDate: latestVOOArrayDate, fundName: "VOO")
                    await NormalizeClosingValuesAA(moc: dataContainer.viewContext, numYears: 1, latestDate: latestVOOArrayDate, fundName: "VOO")
                    await NormalizeClosingValuesAA(moc: dataContainer.viewContext, numYears: 5, latestDate: latestVOOArrayDate, fundName: "VOO")
                } // end if statement
                vooTempValues1 = await FetchContainerValuesAA(moc: dataContainer.viewContext, numYears: 1, latestDate: latestVOOArrayDate, fundName: "VOO")
            } catch {
                print("Error getting VOO data")
            } // end catch
        } // end task
        completionHandler(vooTempValues1, false)
    } // end func
} // end class


Solution

  • The easiest way to fix this is to make vooCompletionHandler into a function:

    func vooCompletionHandler(prices: [TradingDayPrices], loadingComplete: Bool) {
        DispatchQueue.main.async {
            vooValues1 = prices
            isloading = loadingComplete
        }
    }
    

    You'd use the function the same way in SetupVOO(using: vooCompletionHandler)