【问题标题】:How do I async load a text file from URL, then async load images from URLs in the text file? (in swift)如何从 URL 异步加载文本文件,然后从文本文件中的 URL 异步加载图像? (迅速)
【发布时间】:2016-12-30 14:42:15
【问题描述】:

我是 iOS 开发的新手,因此我们将不胜感激。

项目:我正在为 iOS 开发一个 Emoji 风格的键盘。当键盘首次加载时,它会从 Internet 下载一个带有图像 URL 的 .txt 文件(这样我就可以通过更新该 .txt 文件来添加/删除/重新排序图像)。图像 URL 被输入到一个数组中,然后图像 URL 数组用于填充集合视图。

我编写的代码可以运行,但是当我切换到键盘时,系统会等到所有内容都加载完毕(通常为 2-3 秒),然后才会弹出键盘。 我想要的是让键盘在没有图像的情况下立即弹出,然后在图像可用时加载它们 - 这样用户就可以看到键盘工作了。

如何让键盘立即加载,然后下载文本文件,然后下载图片?我找到了很多关于异步下载图片的信息,但我的问题是添加文本下载后稍微复杂一些,我不太明白。

更多信息:

我正在使用 SDWebImage 加载图像,因此它们可以很好地缓存并且应该异步加载,但是我将它包裹在键盘上的方式是等到所有内容都下载后才能显示。

我尝试将下面代码的“do { } catch { }”部分包装在内部 - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { //do-catch code }) - 当我这样做时,键盘会像我想要的那样立即弹出,而不是 2-3 秒来加载图像,这需要 8-10 秒,并且在显示任何图像之前仍会等待所有图像。

下面是我的代码。我通过删除按钮和其他有效的代码来简化代码。此代码有两个 .xib 文件:KeyboardView 和 ImageCollectionViewCell

import UIKit
import MobileCoreServices
import SDWebImage


class ImageCollectionViewCell:UICollectionViewCell {
    @IBOutlet var imgView:UIImageView!
}

class KeyboardViewController: UIInputViewController, UICollectionViewDataSource, UICollectionViewDelegate {

    @IBOutlet var collectionView: UICollectionView!

    let blueMojiUrl = NSURL(string: "http://example.com/list/BlueMojiList.txt")
    var blueMojiArray = NSMutableArray()

    func isOpenAccessGranted() -> Bool {
        // Function to test if Open Access is granted
        return UIPasteboard.generalPasteboard().isKindOfClass(UIPasteboard)
    }


    override func viewDidLoad() {
        super.viewDidLoad()

        let nib = UINib(nibName: "KeyboardView", bundle: nil)
        let objects = nib.instantiateWithOwner(self, options: nil)
        self.view = objects[0] as! UIView;

        self.collectionView.registerNib(UINib(nibName: "ImageCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "ImageCollectionViewCell")


        if (isOpenAccessGranted()) == false {
            // Open Access is NOT granted - display error instructions

        } else {
            // Open Access IS granted

                do {

                self.blueMojiArray = NSMutableArray(array: try NSString(contentsOfURL: self.blueMojiUrl!, usedEncoding: nil).componentsSeparatedByString("\n"));

                self.collectionView.reloadData()

            } catch {
                // Error connecting to server - display error instructions
            }

        }

    } // End ViewDidLoad


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


    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

        let iCell = collectionView.dequeueReusableCellWithReuseIdentifier("ImageCollectionViewCell", forIndexPath: indexPath) as! ImageCollectionViewCell
        let url = NSURL(string: self.blueMojiArray.objectAtIndex(indexPath.row) as! String)

        iCell.imgView.sd_setImageWithURL(url, placeholderImage: UIImage(named: "loading"))

        iCell.layer.cornerRadius = 10.0

        return iCell
    }

}

更新: 感谢您的回答。我能够用 Alamofire 解决我的问题。我将 Alamofire pod 安装到我的项目中。我用来解决问题的具体代码:首先我在顶部添加了import Alamofire,然后我删除了上面的 do { } catch { } 代码并将其替换为

Alamofire.request(.GET, blueMojiUrl!)
                .validate()
                .responseString { response in

                    switch response.result {

                    case .Success:
                        let contents = try? NSString(contentsOfURL: self.blueMojiUrl!, usedEncoding: nil)
                        self.blueMojiArray = NSMutableArray(array: contents!.componentsSeparatedByString("\n"))

                    self.collectionView.reloadData()


                    case .Failure:
                        // Error connecting to server - display error instructions
                    }
            }

现在键盘会立即加载,然后在 2-3 秒内加载图像。

【问题讨论】:

    标签: ios swift asynchronous keyboard


    【解决方案1】:

    【讨论】:

    • 谢谢!这帮助我指出了正确的方向,但我无法自己正确实施。我终于使用 Alamofire(我相信它使用 NSURLSession)得到了我想要的结果,并用我的结果更新了我的问题。
    【解决方案2】:

    我会这样做:

    cellForItemAtIndexPath 调用方法以使用完成处理程序下载当前单元格的图像。在下载完成时,将单元格的图像设置为下载的图像并为此单元格调用方法reloadItemsAtIndexPaths

    示例代码:

    func downloadPlaceholderImage(url: String, completionHandler: (image: UIImage) -> ()) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
            /// download logic
               completionHandler(image: downloadedImage)
            })            
        }
    }
    
    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
       ///
       downloadPlaceHolderImage("url", completionHandler: { image in
         cell.image = image 
         self.collectionView.reloadItemsAtIndexPaths([indexPath])
       })
      ///  
    }
    

    【讨论】:

    • 谢谢!在我的情况下,使用 reloadItemsAtIndexPaths 会导致问题,因为我有几个集合,所以它们堆叠在一起:) 我能够让它与 Alamofire 一起正常工作,我用我的结果更新了我的问题。感谢您的回复,感谢您抽出宝贵时间提供帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多