0

I'm having some trouble with an array. I created an array called 'coins'

var coins = [Coin]()

then appended objects to it within a function

 func getCoinData() {
        AF.request("https://min-api.cryptocompare.com/data/top/mktcapfull?limit=10&tsym=USD", encoding: JSONEncoding.default).responseJSON { response in

            if let json = response.result.value{

                let responseDictionary = json as! [String : Any]
                let data = responseDictionary["Data"] as! [Any]

                for index in data {

                    let coin            = index as! Dictionary<String, Any>
                    let coinInfo        = coin["CoinInfo"] as! Dictionary<String, Any>
                    let displayInfo     = coin["DISPLAY"] as! Dictionary<String, Any>
                    let usdDisplayInfo  = displayInfo["USD"] as! Dictionary<String, Any>

                    let name            = coinInfo["Name"]
                    let fullName        = coinInfo["FullName"]
                    let imageUrl        = coinInfo["ImageUrl"]
                    let price           = usdDisplayInfo["PRICE"]
                    let marketCap       = usdDisplayInfo["MKTCAP"]
                    let change24Hr      = usdDisplayInfo["CHANGE24HOUR"]

                    let newCoin = Coin()

                    if let newCoinName = name, let newCoinFullName = fullName, let newCoinImageUrl = imageUrl, let newCoinPrice = price, let newCoinMarketCap = marketCap, let newCoinChange24hr = change24Hr {
                        let coinName        = newCoinName
                        let coinFullName    = newCoinFullName
                        let coinImageUrl    = newCoinImageUrl
                        let coinPrice       = newCoinPrice
                        let coinMarketCap   = newCoinMarketCap
                        let coinChange24Hr  = newCoinChange24hr

                        newCoin.name        = "\(coinName)"
                        newCoin.fullName    = "\(coinFullName)"
                        newCoin.imageURL    = "\(coinImageUrl)"
                        newCoin.price       = "\(coinPrice)"
                        newCoin.marketCap   = "\(coinMarketCap)"
                        newCoin.change24Hr  = "\(coinChange24Hr)"

                        self.coins.append(newCoin)
                    }
                }
            }
        }
    }

When i print 'self.coins.count' within the scope of the function i can see the count incrementing. Outside the function it's reading 0 items in the array.

1 Answers1

2

Written for Swift 5

The problem is that you have a URL request which is Asynchronous. This means that the task is not waited for to complete.

In your problem, inside the function coins is printed after it has been assigned, after the URL request. However, when coins is printed outside the function, it is printed before it has been changed, as the URL request has not yet completed.

To solve this, you need to create a completion handler. A basic one is shown here:

// Our errors which could occur
enum SomeError: Error { case unknown }

// Function which is ASYNCHRONOUS
func someAsyncFunction(completion: @escaping (Result<Int, SomeError>) -> ()) {
    // Temporary for this example
    let success = true
    let myNum = 3
    
    // Return value if it is a success, otherwise return the error
    if success {
        completion(.success(myNum))
    } else {
        completion(.failure(.unknown))
    }
}


// Call
someAsyncFunction { (result) in
    print("Result:  \(result)")
    /* PRINT COINS HERE */
}

See a full guide on completion handlers using Result in Swift 5 at hackingwithswift.com.

Community
  • 1
  • 1
George
  • 25,988
  • 10
  • 79
  • 133