BLACK FRIDAY SALE: Save big on all my Swift books and bundles! >>

Cannot use instance member 'property' within property initializer; property initializers run before 'self' is available

Forums > SwiftUI

I'm making a weather app and wanted to implement changing location to different cities and I'm getting this error: Cannot use instance member 'city' within property initializer; property initializers run before 'self' is available Is there some way to initialize this "city" variable before the property initializer? Here's my code:

struct API {
    var city = "London"

    //: [Get your API Key here](https://openweathermap.org/api "Open Weather Map API")
    static let key = URLQueryItem(name: "APPID", value: .apiKey)

    //MARK: URL EndPoints
    static var baseURL = URLComponents(string: .url)
    var searchString = URLQueryItem(name: .query, value: city)

    //Basic Weather URL
    func locationForecast() -> URL?  {
        API.baseURL?.queryItems?.append(searchString)
        API.baseURL?.queryItems?.append(API.key)
        return API.baseURL?.url
    }
}

   

Capslock puts the horse before the cart:

Is there some way to initialize this "city" variable before the property initializer?

Commit this rule to memory! All vars in a struct must be initialized before you can use any of them.

You are attempting to initialize the searchString var using the city var. You can't use the city var until all the vars in the struct have been initialized.

This might be a great use case for computed vars.

struct API {
    // Cool! Define a city! It's the first to get initialized.
    // Plot twist!  It may NOT be the first var initialized.
    var city = "Cottington" // Don't forget your towel!

    // Swift must initialize ALL vars in a struct, 
    // before the struct can be used.
    // Whilst this is AFTER the city declaration above, Swift does
    // NOT guarantee the order in which vars are initialized.
    // Consequently, Swift cannot create the var badQueryItem
    // because it uses another var named city.
    // Indeed, city may not yet exist.
    var badQueryItem = URLQueryItem(name: "City", value: city)

    // Computed vars are not calculated until needed.
    // This will happen after a struct is initialized.
    var queryCityItem: URLQueryItem {
        URLQueryItem(name: "City", value: city)
    }
}

Keep coding!

Please return here and share with the community how you solved this problem.

Variable Names

Also, take a moment and review your var names.

If my team were providing feedback during a sprint code review, we might question variable and function names.

  1. Why does the function locationForecast() return a URL? Its name suggests it returns a weather forecast for a location! Consider renaming to locationURL and perhaps making it a computed var.
  2. Variable searchString is not a String at all. It's a URLQueryItem object. Plus it's configured only for a city. Consider renaming to cityQueryItem.

   

hi,

the problem is that you are trying to use the value of API.city in URLQueryItem to set the value of API.searchString (i.e., before the struct is completely initialized).

the following should work: use an explicit initializer. (by the way, i assume you have defined String.query, String.url, and String.apiKey.)

struct API {

    static let key = URLQueryItem(name: "APPID", value: .apiKey)
    static var baseURL = URLComponents(string: .url)

    var city: String
    var searchString: URLQueryItem

    init(city: String) {
        self.city = "London"
        searchString = URLQueryItem(name: .query, value: city)
    }

    func locationForecast() -> URL?  {
        API.baseURL?.queryItems?.append(searchString)
        API.baseURL?.queryItems?.append(API.key)
        return API.baseURL?.url
    }
}

hope that helps,

DMG

   

Hacking with Swift is sponsored by RevenueCat

SPONSORED In-app subscriptions are a pain to implement, hard to test, and full of edge cases. RevenueCat makes it straightforward and reliable so you can get back to building your app. Oh, and it's free if your app makes less than $10k/mo.

Learn more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.