繁体   English   中英

iOS WatchKit / Swift-延迟在WKInterfaceTable行中加载图像

[英]iOS WatchKit / Swift - Lazy Loading images in WKInterfaceTable rows

在我的Apple Watch应用程序中,我有一张约25行的表格,每个表格都有几行文字和一张图片,需要从互联网上加载。 与Instagram风格的供稿类似,但这些是每个大约8k的个人资料图片。

当我基于传入的JSON数据构建表时,我利用WatchKit的内置图像缓存正确地进行了所有操作,以减少不必要的网络流量。

该应用程序“运行”,并且图像正确显示。 但是问题是视图需要10到20秒钟的时间才能准备好与用户进行交互。 在这10到20秒之前,滚动缓慢,并且在加载完所有图像之前,按钮不执行任何操作。

我想要的是一种在用户向下滚动时延迟加载图像的方法。

我已经尝试实现分页解决方案,但是它也有缺点,并且不能完全解决我原来的问题。

如果仅填充文本位(无图像),则该表会立即显示并可以进行交互。


***更新:Mike Swanson在下面的回答非常彻底,并且确实解决了我的大部分问题。 呆滞和阻碍已经消失。

我想将最终代码发布给其他遇到类似问题的人。 具体来说,我想展示如何实现后台调度。

我现在还将在主线程中临时将图像设置为占位符以显示活动。 实际图像加载并传输到手表后,它将立即更换。 我还改进了图像缓存键,以便在上载新图像时错过它。

新代码:

let qualityOfServiceClass = QOS_CLASS_BACKGROUND
let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)

i = 0
for p in self.profiles {
    if let profileId = p["id"] as? NSNumber {
        var profileIdStr = "\(profileId)"
        let row = self.profilesTable.rowControllerAtIndex(i) as! WatchProfileRow

        if let hasImage = p["has_image"] as? NSNumber {
            let profileImageCacheKey = "\(profileIdStr)-\(hasImage)"

            // if the image is already in cache, show it
            if self.device.cachedImages[profileImageCacheKey] != nil {
                row.profileImageThumbnail.setImageNamed(profileImageCacheKey)

                // otherwise, get the image from the cdn and cache it
            } else {
                if let imageHost = self.imageHost as String! {
                    var imageURL = NSURL(string: NSString(format: "%@%@-thumbnail?version=%@", imageHost, profileId, hasImage) as String)

                    var imageRequest = NSURLRequest(URL: imageURL!)

                    NSURLConnection.sendAsynchronousRequest(imageRequest, queue: NSOperationQueue.mainQueue()) {
                        (response, data, error) -> Void in
                        if error == nil {
                            row.profileImageThumbnail.setImageNamed("profile-placeholder")

                            dispatch_async(backgroundQueue, {
                                self.device.addCachedImageWithData(data, name: profileImageCacheKey)

                                dispatch_async(dispatch_get_main_queue(), { () -> Void in
                                    row.profileImageThumbnail.setImageNamed(profileImageCacheKey)
                                })
                            })
                        }
                    }
                } else {
                    row.profileImageThumbnail.setImageNamed("profile-placeholder")
                }
            }
        } else {
            row.profileImageThumbnail.setImageNamed("profile-placeholder")
        }

    }

    i++
}

原始代码:

i = 0
for p in self.profiles {
    if let profileId = p["id"] as? NSNumber {
        var profileIdStr = "\(profileId)"
        let row = self.profilesTable.rowControllerAtIndex(i) as! WatchProfileRow

        if let hasImage = p["has_image"] as? NSNumber {

            // if the image is already in cache, show it
            if self.device.cachedImages[profileIdStr] != nil {
                row.profileImageThumbnail.setImageNamed(profileIdStr)

            // otherwise, get the image from the cdn and cache it
            } else {
                if let imageHost = self.imageHost as String! {
                    var imageURL = NSURL(string: NSString(format: "%@%@-thumbnail?version=%@", imageHost, profileId, hasImage) as String)

                    var imageRequest = NSURLRequest(URL: imageURL!)

                    NSURLConnection.sendAsynchronousRequest(imageRequest, queue: NSOperationQueue.mainQueue()) {
                        (response, data, error) -> Void in
                        if error == nil {
                            var image = UIImage(data: data)
                            row.profileImageThumbnail.setImage(image)

                            self.device.addCachedImage(image!, name: profileIdStr)
                        }
                    }
                } else {
                    row.profileImageThumbnail.setImageNamed("profile-placeholder")
                }
            }
        } else {
            row.profileImageThumbnail.setImageNamed("profile-placeholder")
        }   
    }        
    i++
}

首先,有在WatchKit没有方法来确定在当前位置WKInterfaceTable 这意味着您使用的任何逻辑都必须解决该事实。

其次,看起来您要发送异步网络请求,然后在有数据时使用setImage setImage在将图像传输到设备之前将其编码为PNG,并且在您现有的代码中,这是在主线程上发生的。 如果不需要PNG图像,我会考虑使用setImageData发送JPEG编码的数据,以进一步减少需要传输到Watch的字节数。

最后,看来您正在双重传输图像。 一次使用setImage ,一次使用addCachedImage 收到图像后,建议您分派到后台线程,然后使用WKInterfaceDeviceaddCachedImageWithData (可以在后台线程上安全使用)来发送数据。 然后,在使用setImageNamed设置现在缓存的图像之前,分派回主线程。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM