self' captured by a closure before all members were initialized
I'd hazard to guess that your are running into a concurrency problem. You are probably trying to access your object's properties before the asynchronous call to the DarkSkyClient returns (my apologies in advance if I got this wrong). i.e., the order of events is...
- Weather object is initialized, setting temp to 0
- Call to DarkSkyClient begins, runs in the background
- Read temp variable - hey, it's 0!
- Call to DarkSkyClient completes, sets the temp to the value you really wanted. Bad
So what you really need to do is switch to an inversion of control pattern:
class Weather {
var temp: Float
var condition: String
var wind: Float
var precip: Float
init(forecast: Forecast) {
temp = (forecast.currently?.temperature)!
condition = (forecast.currently?.summary)!
wind = (forecast.currently?.windSpeed)!
precip = (forecast.currently?.precipitationProbability)!
}
static func getWeather() {
DarkSkyClient(apiKey: "<api key>").getForecast(latitude: Utils().getLat(), longitude: Utils().getLong()) { result in
switch result {
case .success(let currentForecast, _):
let weather = Weather(forecast: currentForecast)
// Display the weather somewhere
doSomethingWith(weather: weather)
case .failure(let error):
print(error)
}
}
}
}
If you're not familiar with developing with asynchronous APIs it's worth your while to read up on the subject; it can be very tricky (sadly, I don't have any recommendations for a good primer).
Hope this helps!
self captured by a closure before all members were initialized - but I did initialize them
While I'm not entirely sure why Swift doesn't allow this (something to do with capturing self
to create the closure before the actual call to super.init
is made), I do at least know of a workaround for it. Capture a weak local variable instead, and after the call to super.init
set that local variable to self
:
class MyDataSource: UITableViewDiffableDataSource<String,String> {
var string : String?
init(string:String?) {
self.string = string
weak var selfWorkaround: MyDataSource?
super.init(tableView: UITableView()) { (_, _, _) -> UITableViewCell? in
print(selfWorkaround?.string)
return nil
}
selfWorkaround = self
}
}
The only problem with this, though, is that if the closure is executed during the call to super.init
, then selfWorkaround
would be nil inside the closure and you may get unexpected results. (In this case, though, I don't think it is - so you should be safe to do this.)
Edit: The reason we make the local variable weak
is to prevent the self
object from being leaked.
Self captured by a closure before all members were initialized
The problem is that you have some variables in your class that are only declared, but not initialized by the time your capture is called, where you are referring to self
.
Declaring a variable: var a: Int
and initializing it: var a:Int = 0
or var a:Int? = nil
are not the same.
All variables of your class need to be initialized (given an initial value) before you could refer to self
.
Strange 'self' captured by a closure before all members were initialized error
The problem is in bExpectedValue
. That's an instance property on B
. That interacts with the definition of &&
on Bool:
static func && (lhs: Bool, rhs: @autoclosure () throws -> Bool) rethrows -> Bool
The @autoclosure
makes the b == bExpectedValue
into a closure, capturing it as self.bExpectedValue
. That's not allowed before initialization is complete. (The closure here is to allow short-circuiting. The rhs closure is not evaluated if lhs is false.)
This is pretty awkward (see SR-944 that MartinR references for a little discussion about it).
If bExpectedValue
were static
, or if it were moved outside the class definition, then this wouldn't be an issue. The following approach will also fix it:
override init(a: String, b: String) {
let goodA = a == aExpectedValue
let goodB = b == bExpectedValue
c = goodA && goodB
super.init(a: a, b: b)
}
how to deal with 'Self captured by closure before being initialized'
The problem with your code is that you have declared the variable as a constant, and swift should always have constants initialized within the init method. But, here you have dependent kind of requirement, readyHandler property is a constant which has to be initialized in order to create object but then, you are using self inside it which is not initialized, you can see a cyclic requirement.
You can directly get rid of this, if you use optional or implicitly unwrapped optional in which case, swift need not have initial value at the phase of instantiation.
class A {
class ReadyHandler { // fires off the callback when needed
let callback: ()->Void
init(callback: @escaping ()->Void) {
self.callback = callback
}
}
var readyHandler: ReadyHandler!
var ready = false
init() {
readyHandler = ReadyHandler(callback: {self.ready = true})
}
}
You can create a also use lazy property for your readyHandler which gets initialized first time it is used.
class A {
class ReadyHandler {
let callback: ()->Void
init(callback: @escaping ()->Void) {
self.callback = callback
}
}
var ready = false
lazy var readyHandler: ReadyHandler = {
return ReadyHandler(callback: { [unowned self] in
self.ready = true
})
}()
}
Swift5(+RxSwift) 'self' captured by a closure before all members were initialized
You shouldn't tie two independent observable streams to each other with some random block of "temp" memory. The two streams depend on inputObservable
and that should be made clear. Also, your view model can be greatly simplified...
final class ViewModel {
let validationText: Observable<String>
let getObservable: Observable<String>
init(inputObservable: Observable<String?>, changeButtonClicked: Observable<Void>, model: ModelProtocol, api: apiProtocol = APICntl()) {
let translatedText = inputObservable.share() // this line is unnecessary if `inputObservable` is already hot.
self.validationText = translatedText
.flatMap { input in
return model
.validate(text: input)
.map { "" }
.catchError { error in .just((error as? ModelError)?.errorLabel ?? error.localizedDescription) }
}
.startWith(ModelError.invalidBlank.errorLabel)
self.getObservable = changeButtonClicked
.withLatestFrom(translatedText)
.compactMap { $0 }
.flatMap { translatedText in
return api
.fetch(text: translatedText)
.catchError { error in .just((error as? ModelError)?.errorLabel ?? error.localizedDescription) }
}
}
}
Initialized variable: 'self' captured by a closure before all members were initialized
Try to use this block
{ [unowned self] (snapshot) in
// snapshot error checking
// users is [String]
self.users = users
})
or
{ [weak self] (snapshot) in
// snapshot error checking
// users is [String]
self?.users = users
})
Related Topics
Swift 4.2 Setter Getter, All Paths Through This Function Will Call Itself
Error: Use of Unresolved Identifier 'Process'
Argument Labels Do Not Match Any Available Overloads
Why How to Use Codable with a Project Language Version of Swift 3.3
How to Make the Memberwise Initialiser Public, by Default, for Structs in Swift
Exponentiation Operator in Swift
Getting Dyld_Fatal_Error After Updating to Xcode 6 Beta 4 Using Swift
When to Use [Self] VS [Weak Self] in Swift Blocks
How to Play Multiple Audio Files Simultaneously Using Avplayer
Trying to Stream Audio from Microphone to Another Phone via Multipeer Connectivity
Swiftyjson - Call Can Throw, But It Is Marked with 'Try' and the Error Is Not Handled
How to Remove Optional from String Value Swift
How to Add an Optional String Extension