如何使用swift 3.1

时间:2017-07-19 15:24:02

标签: ios image uitableview dictionary swift3

我是swift的新手,需要一些帮助来从URL中获取图像并将它们存储到字典中以引用到UITableView中。我已经检查了各种线程,但找不到满足特定需求的场景。

我目前将字典中的产品名称作为关键字,并将图像网址链接到每个名称:

let productLibrary = ["Product name 1":"http://www.website.com/image1.jpg", 
"Product name 2":"http://www.website.com/image2.jpg"]

我需要将实际图像放入具有相同产品名称的字典中,作为添加到UITableView的键。

我目前使用以下代码将图像直接加载到tableView cellForRowAt函数中,但这会使表视图无响应,因为每次TableView刷新时都会加载图像:

cell.imageView?.image = UIImage(data: try! Data(contentsOf: URL(string:
productLibrary[mainPlaces[indexPath.row]]!)!))

mainPlaces是productLibrary词典中列出的一系列产品的数组。最初在字典中预先加载图像肯定会减少加载时间并使UITableView像我需要的那样响应。

非常感谢任何帮助!

@Samarth,我已经按照下面的建议实现了你的代码(只是将扩展名直接复制到ViewController类上面的ViewController.swift文件的根目录。

其余的,我已经粘贴在ViewController类下面,如下所示,但它实际上还没有在tableview中显示图像。

我试图像你建议的那样做,但也许我错过了一些明显的东西。很抱歉很多回复,但我似乎无法让它工作。请参阅下面的确切代码:

internal func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "Cell")

    cell.textLabel?.text = mainPlaces[indexPath.row]

    downloadImage(url: URL(string: productLibrary[mainPlaces[indexPath.row]]!)!)

    cell.imageView?.downloadedFrom(link: productLibrary[mainPlaces[indexPath.row]]!)

    return cell

}

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    performSegue(withIdentifier: "ProductSelect", sender: nil)

        globalURL = url[mainPlaces[indexPath.row]]!

}

func getDataFromUrl(url: URL, completion: @escaping (_ data: Data?, _  response: URLResponse?, _ error: Error?) -> Void) {
    URLSession.shared.dataTask(with: url) {
        (data, response, error) in
        completion(data, response, error)
        }.resume()
}

func downloadImage(url: URL) {
    print("Download Started")
    getDataFromUrl(url: url) { (data, response, error)  in
        guard let data = data, error == nil else { return }
        print(response?.suggestedFilename ?? url.lastPathComponent)
        print("Download Finished")
        DispatchQueue.main.async() { () -> Void in

            // self.imageView.image = UIImage(data: data)
            /* If you want to load the image in a table view cell then you have to define the table view cell over here and then set the image on that cell */
            // Define you table view cell over here and then write

            let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "Cell")

            cell.imageView?.image = UIImage(data: data)

        }
    }
}

2 个答案:

答案 0 :(得分:3)

您可以在项目中同步或异步加载图像。

同步:表示您的数据正在主线程上加载,因此在您的数据加载之前,您的主线程(UI线程)将被阻止。这就是项目中发生的事情

异步:表示您的数据正在加载到UI线程以外的其他线程上,因此不会阻止UI并且您的数据加载是在后台完成的。

尝试此示例加载图像异步

<强>异步:

使用完成处理程序创建一个方法以从您的网址获取图像数据

func getDataFromUrl(url: URL, completion: @escaping (_ data: Data?, _  response: URLResponse?, _ error: Error?) -> Void) {
    URLSession.shared.dataTask(with: url) {
        (data, response, error) in
        completion(data, response, error)
    }.resume()
}

创建下载图像的方法(启动任务)

func downloadImage(url: URL) {
    print("Download Started")
    getDataFromUrl(url: url) { (data, response, error)  in
        guard let data = data, error == nil else { return }
        print(response?.suggestedFilename ?? url.lastPathComponent)
        print("Download Finished")
        DispatchQueue.main.async() { () -> Void in

           // self.imageView.image = UIImage(data: data)
   /* If you want to load the image in a table view cell then you have to define the table view cell over here and then set the image on that cell */
           // Define you table view cell over here and then write 
           //      cell.imageView?.image = UIImage(data: data)

        }
    }
}

<强>用法:

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    print("Begin of code")
    if let checkedUrl = URL(string: "your image url") {
        imageView.contentMode = .scaleAspectFit
        downloadImage(url: checkedUrl)
    }
    print("End of code. The image will continue downloading in the background and it will be loaded when it ends.")
}

<强>扩展:

extension UIImageView {
    func downloadedFrom(url: URL, contentMode mode: UIViewContentMode = .scaleAspectFit) {
        contentMode = mode
        URLSession.shared.dataTask(with: url) { (data, response, error) in
            guard
                let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
                let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
                let data = data, error == nil,
                let image = UIImage(data: data)
            else { return }
            DispatchQueue.main.async() { () -> Void in
                self.image = image
            }
        }.resume()
    }
    func downloadedFrom(link: String, contentMode mode: UIViewContentMode = .scaleAspectFit) {
        guard let url = URL(string: link) else { return }
        downloadedFrom(url: url, contentMode: mode)
    }
}

<强>用法:

imageView.downloadedFrom(link: "image url")

提出您的问题

在表格视图单元格中加载图像时执行此操作:

 cell.imageView?.downloadedFrom(link: productLibrary[mainPlaces[indexPath.row]]! )

答案 1 :(得分:0)

我设法在viewDidLoad方法中使用带有for循环的dataTask方法来实现这一点,然后更新了一个全局字典,因此当我切换viewControllers时它不必重新填充,并且因为它不是&#39;在tableView方法中,表在图像加载时保持响应。 url仍然存储为链接到产品的字典,然后字典将实际的UIImage填充为字典,产品名称为密钥。代码如下:

if images.count == 0 {
    for product in productLibrary {

        let picurl = URL(string: product.value)

        let request = NSMutableURLRequest(url: picurl!)

        let task = URLSession.shared.dataTask(with: request as URLRequest) {
            data, response, error in

            if error != nil {

                print(error)

            } else {

                if let data = data {

                    if let tempImage = UIImage(data: data) {

                        images.updateValue(tempImage, forKey: product.key)

                    }

                }


            }

        }

        task.resume()


    }

    }

我希望这会有所帮助,因为这正是我在提出这个问题时希望实现的目标,并且很容易实现。

感谢所有贡献的人。