提问者:小点点

斯威夫特:拖放,保存谷歌图片中的图片网址


我正在尝试创建一个应用程序,该应用程序包含一个集合视图,其中拖动了图像。

我在一个双显示屏中打开谷歌图像,搜索“海豹”,并将海豹的第一张图像拖到我的应用程序的视图控制器上。我的应用程序应该保存图像的url。集合视图中的每个单元格都会从保存的url中获得一个url。设置url后,单元格从url中检索图像并将图像放置在其内部。

问题是错误的网址被带走了。可以将url转换成数据,但是不能将数据转换成UIImage。从拖放中保存的url不是图像的url,它似乎是google搜索或其他内容的url。

我需要能够保存图像的正确url,以便ImageCell可以从url加载图像。

当我在浏览器中输入网址时,我看到了这样一个页面。

ImageView控制器

import UIKit

class ImageViewController: UIViewController{

    @IBOutlet weak var collectionView: UICollectionView!

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    var gallery = [URL]()

}

extension ImageViewController: UICollectionViewDelegate, UICollectionViewDataSource{

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return gallery.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCell", for: indexPath) as! ImageCell
        cell.url = gallery[indexPath.item]
        return cell
    }
}

extension ImageViewController: UICollectionViewDropDelegate{

    func collectionView(_ collectionView: UICollectionView, canHandle session: UIDropSession) -> Bool {
        return session.canLoadObjects(ofClass: NSURL.self) && session.canLoadObjects(ofClass: UIImage.self)
    }

    func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal {
        return UICollectionViewDropProposal(operation: .copy)
    }

    func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) {

        // Get the destion index path, if there's none set, just insert at the beginning
        let destinationIndexPath = coordinator.destinationIndexPath ?? IndexPath(item: 0, section: 0)

        // Process all items being dragged
        for item in coordinator.items {

                // External drops must provide url and an image that we'll use to get an aspect-ratio
                var url: URL?

                // Get the URL
                item.dragItem.itemProvider.loadObject(ofClass: NSURL.self) { [weak self] (provider, error) in

                    url = provider as? URL  //Check that url is valid

                    // If both url and ratio were provided, perform the actual drop
                    if url != nil{
                        DispatchQueue.main.async {
                            collectionView.performBatchUpdates({
                                // Update model
                                self?.gallery.insert(url!, at: destinationIndexPath.item)

                                // Update view
                                collectionView.insertItems(at: [destinationIndexPath])

                                // Animates the item to the specified index path in the collection view.
                                coordinator.drop(item.dragItem, toItemAt: destinationIndexPath)
                            })
                        }
                    }
                }
            }

    }

}

图像单元

class ImageCell: UICollectionViewCell{
    var url: URL?{
        didSet{
            self.fetchImage(withURL: url!)
        }
    }
    @IBOutlet var imageView: UIImageView!

    private func fetchImage(withURL url: URL) {
        DispatchQueue.global(qos: .userInitiated).async { [weak self] in
            guard let data = try? Data(contentsOf: url) else {
                return
            }

            guard let image = UIImage(data: data) else {
                print("Couldn't convert data to UIImage")
                print("The url is")
                print(url)
                return
            }

            // If by the time the async. fetch finishes, the imageURL is still the same, update the UI (in the main queue)
            if self?.url == url {
                DispatchQueue.main.async {
                    self?.imageView.image = image
                }
            }
        }
    }

}

开源代码库

这是我在 github 上的项目


共1个答案

匿名用户

要从从谷歌图像拖放提供的url中提取图像url,可以将这些扩展添加到url中。然后,在保存url的变量(url)上,可以使用url!访问图像url!。imageURL而不仅仅是url

extension URL {
    var imageURL: URL {
        if let url = UIImage.urlToStoreLocallyAsJPEG(named: self.path) {
            // this was created using UIImage.storeLocallyAsJPEG
            return url
        } else {
            // check to see if there is an embedded imgurl reference
            for query in query?.components(separatedBy: "&") ?? [] {
                let queryComponents = query.components(separatedBy: "=")
                if queryComponents.count == 2 {
                    if queryComponents[0] == "imgurl", let url = URL(string: queryComponents[1].removingPercentEncoding ?? "") {
                        return url
                    }
                }
            }
            return self.baseURL ?? self
        }
    }
}

extension UIImage
{
    private static let localImagesDirectory = "UIImage.storeLocallyAsJPEG"

    static func urlToStoreLocallyAsJPEG(named: String) -> URL? {
        var name = named
        let pathComponents = named.components(separatedBy: "/")
        if pathComponents.count > 1 {
            if pathComponents[pathComponents.count-2] == localImagesDirectory {
                name = pathComponents.last!
            } else {
                return nil
            }
        }
        if var url = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first {
            url = url.appendingPathComponent(localImagesDirectory)
            do {
                try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true)
                url = url.appendingPathComponent(name)
                if url.pathExtension != "jpg" {
                    url = url.appendingPathExtension("jpg")
                }
                return url
            } catch let error {
                print("UIImage.urlToStoreLocallyAsJPEG \(error)")
            }
        }
        return nil
    }

    func storeLocallyAsJPEG(named name: String) -> URL? {
        if let imageData = self.jpegData(compressionQuality: 1.0) {
            if let url = UIImage.urlToStoreLocallyAsJPEG(named: name) {
                do {
                    try imageData.write(to: url)
                    return url
                } catch let error {
                    print("UIImage.storeLocallyAsJPEG \(error)")
                }
            }
        }
        return nil
    }
}