Variable captured by closure before being initialized
You need to initialize the variable before use it inside a closure:
As per apple documentation
If you use a closure to initialize a property, remember that the rest
of the instance has not yet been initialized at the point that the
closure is executed. This means that you cannot access any other
property values from within your closure, even if those properties
have default values. You also cannot use the implicit self property,
or call any of the instance’s methods.
The command var numberOfGames: Int
just declare it to initialize you can use var numberOfGames = Int()
or var numberOfGames:Int = 0
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
var user: PFUser!
var numberOfGames:Int = 0
var query = PFQuery.orQueryWithSubqueries([userQuery, userQuery2, currentUserQuery, currentUserQuery2])
query.findObjectsInBackgroundWithBlock{
(results: [AnyObject]?, error: NSError?) -> Void in
if error != nil {
println(error)
}
if error == nil{
if results != nil{
println(results)
numberOfGames = results!.count as Int
}
}
}
return numberOfGames
}
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
})
}()
}
What causes 'Constant captured by a closure before being initialized' error
The reason for the error message is that the nil-coalescing operator
is defined as
public func ??<T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T
and does a "auto closure" on the second argument (in order to get
a short-circuiting behaviour). So
self.value = dict["bar"] as? String ?? _defaultValue
is transformed by the compiler to
self.value = dict["bar"] as? String ?? { self._defaultValue }()
and here the compiler complains because self
is captured before
being fully initialised. (The error messages are slightly different
between Swift 2 and Swift 3).
Possible workarounds. You can assign the property to a local variable first:
init(dict: NSDictionary){
let defValue = _defaultValue
self.value = dict["bar"] as? String! ?? defValue
}
Or you can make it a static property of the class:
class Foo {
static let _defaultValue = "N/A"
let value: String
init(dict: NSDictionary) {
self.value = dict["bar"] as? String ?? Foo._defaultValue
}
}
Or replace ??
by an if-statement:
class Foo {
let _defaultValue = "N/A"
let value: String
init (dict: NSDictionary) {
if let value = dict["bar"] as? String {
self.value = value
} else {
self.value = _defaultValue
}
}
}
Addendum: Related resources:
- Autoclosure of self in initializers in the Swift forum.
- SR-944 Cannot use 'self' in RHS of && before all properties are initialized bug report.
Quote from the bug report:
Jordan Rose: This is true since && is implemented using @autoclosure, but it's certainly suboptimal.
Variable (results) captured by a closure before being initialized
Error is because you are not initializing the results array,
simple solution can be this
declare your results array like this
var results = [Any]()
I think you should do this:
you should declare results as instance variable like this outside viewDidLoad
method
var results = [Any]()
Then use this variable inside closure as follows because I think you need this result in other parts of your code
self.results.append(result)
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.
Variable 'newBalance' captured by a closure before being initialized - Firestore data fetch function - SwiftUI
You need a completion
func getBalance(uid: String,completion:@escaping(Double) -> ()) {
FirebaseManager.shared.firestore.collection("users").document(uid).getDocument{ snapshot, error in
guard let data = snapshot?.data() else {self.errorMessage = "No data found"
return}
let balance = data["balance"] as? Double ?? 0
print("Function balance \(balance)")
completion(balance)
}
}
Call
getBalance(uid:<#value#>) { balance in
print(balance)
}
OR with SwiftUI use @published
@published var newBalance: Double?
func getBalance(uid: String) {
FirebaseManager.shared.firestore.collection("users").document(uid).getDocument{ snapshot, error in
guard let data = snapshot?.data() else {self.errorMessage = "No data found"
return}
let balance = data["balance"] as? Double ?? 0
print("Function balance \(balance)")
self.newBalance = balance
}
}
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!
Related Topics
Convert String to Cgfloat in Swift
Hide Tab Bar in View with Push
Realitykit - Set Text Programmatically of an Entity of Reality Composer
Swift: Dictionary Access via Index
How to Call Initializer for Subclass of Generic Type
How to Use Swift Package Manager in Xcode 9 Playground
Delegate Using Container View in Swift
Single and Double Taps on Uitableviewcell in Swift 3
Why Does My Pfanalytics Not Have Trackappopenewithlaunchoptions Function? (iOS Swift)
Bitwise Operations with Cgbitmapinfo and Cgimagealphainfo
Value for Swift_Version Cannot Be Empty
Show/Hide Password - How to Add This Feature
How to Create Custom Uimenucontroller with Only Custom Items Other Than Default
How to Save Cgimage to Data in Swift
iOS 11 Black Bar Appears on Navigation Bar When Pushing View Controller
What's the Best Approach to Prefill Core Data Store When Using Nspersistentcloudkitcontainer