Reputation: 141
Xcode 8.1, Swift 2.3, iOS 10.1, And I use Firebase
I am not access data outside closure. I want to get downloadURL1 and downloadURL2, like self.url1 = downloadURL1
But downloadURL1 is nil outside closure.
storageRef.child(filePath1).putData(data1, metadata: metaData) { (metadata1, error1) in
if let error = error1 {
print(error.localizedDescription)
return
} else {
let downloadURL1 = metadata1!.downloadURL()!.absoluteString
}
}
storageRef.child(filePath2).putData(data2, metadata: metaData) { (metadata2, error2) in
if let error = error2 {
print(error.localizedDescription)
return
} else {
let downloadURL2 = metadata2!.downloadURL()!.absoluteString
}
}
Upvotes: 1
Views: 101
Reputation: 438232
You say:
downloadURL1
isnil
outside closure.
Yes, that makes sense, because this closure runs asynchronously (i.e. later). You can only use it from within the closure (or from some task initiated when the closure is done).
For example, if you want to do something with these two download only when they're both done, use would dispatch group:
var downloadURL1: String?
var downloadURL2: String?
let group = dispatch_group_create()
dispatch_group_enter(group)
storageRef.child(filePath1).putData(data1, metadata: metaData) { (metadata1, error1) in
defer { dispatch_group_leave(group) }
if let error = error1 {
print(error.localizedDescription)
return
} else {
downloadURL1 = metadata1!.downloadURL()!.absoluteString
}
}
dispatch_group_enter(group)
storageRef.child(filePath2).putData(data2, metadata: metaData) { (metadata2, error2) in
defer { dispatch_group_leave(group) }
if let error = error2 {
print(error.localizedDescription)
return
} else {
downloadURL2 = metadata2!.downloadURL()!.absoluteString
}
}
dispatch_group_notify(group, dispatch_get_main_queue()) {
// you use `downloadURL1` and `downloadURL2` here
}
// but not here
Upvotes: 1
Reputation: 988
If I get your right, you're saying that you can't downloadURL1 and downloadURL2's values outside of your closures ?
Well, if that's so, it's perfectly normal. You should rather declare your variables outside of the closure, before. But trying to use the values of these two variable outside the closure won't work, because it's asynchronous.
So you might also want to use their didSet properties. But in this case, why use downloadURL1 and downloadURL2 at all and not directly do something like that ?
var url1: String? {
didSet {
// Do whatever you want, like call a function, once url1 is set
}
}
var url2: String? {
didSet {
// Do whatever you want, like call a function, once url2 is set
}
}
storageRef.child(filePath1).putData(data1, metadata: metaData) { (metadata1, error1) in
if let error = error1 {
print(error.localizedDescription)
return
} else if let downloadURL1 = metadata1?.downloadURL()?.absoluteString {
// Just to make sure it isn't nil
self.url1 = downloadURL1
}
}
storageRef.child(filePath2).putData(data2, metadata: metaData) { (metadata2, error2) in
if let error = error2 {
print(error.localizedDescription)
return
} else if let downloadURL2 = metadata2?.downloadURL()?.absoluteString {
self.url2 = downloadURL2
}
}
But maybe I didn't understand your question at all ?
Edit: I assumed you're using all this inside a viewController or a class of some sort
Upvotes: 1