I write some code to show an image dragged from other apps(such as web browser, photos, etc). I make a delegate to perform the drop.
If DropInfo has an image item, I will try to retrieve the data as uiimage by NSItemProvider.loadObject first. If errors occur during loading, I will ask DropInfo again whether it has a url item. If the answer is YES, I will try to retrieve URL by NSItemProvider.loadObject.
It means the second loadObject will be nested in the first one. When running the simulator, I find the second loadObject completion handler is never called which is supposed to be called when I try to retrieve URL. Do I miss anything?
import SwiftUI
import Combine
struct ContentView: View{
@State private var img: UIImage?
var body: some View{
Image(uiImage: img != nil ? img! : UIImage(systemName: "photo")!)
.resizable()
.scaledToFit()
.onDrop(of: [.image], delegate: ImageDropController(img: $img))
}
}
class ImageDropController: DropDelegate{
@Binding var img: UIImage?
init(img: Binding<UIImage?>) {
_img = img
}
func performDrop(info: DropInfo) -> Bool {
if getImgFromImage(info: info){
return true
}else{
return false
}
}
func getImgFromImage(info: DropInfo) -> Bool{
guard info.hasItemsConforming(to: [.image]) else {
return getImgFromUrl(info: info)
}
createImgFromImage(from: info.itemProviders(for: [.image]).first!,info: info)
return true
}
func createImgFromImage(from provider: NSItemProvider, info: DropInfo){
provider.loadObject(ofClass: UIImage.self) { image, error in
var unwrappedImage: UIImage?
if let error = error {
print("unwrapImage failed: ", error.localizedDescription)
_ = self.getImgFromUrl(info: info)
} else {
unwrappedImage = image as? UIImage
}
if let image = unwrappedImage{
DispatchQueue.main.async {
self.img = image
}
}
}
}
func getImgFromUrl(info: DropInfo) -> Bool{
guard info.hasItemsConforming(to: [.url]) else {
return false
}
createImgFromUrl(from: info.itemProviders(for: [.url]).first!)
return true
}
private func createImgFromUrl(from provider: NSItemProvider){
var fetchUrl: URL?
print("create from url")
_ = provider.loadObject(ofClass: URL.self) { url, error in
print("nested handler") <<------- never be called
if let error = error {
print("unwrapUrl failed: ", error.localizedDescription)
} else {
fetchUrl = url
print("url", fetchUrl?.description)
}
if let url = fetchUrl{
// Do some data fetch work using url
}
}
}
}