在我的Apple Watch应用中,我有一个表格,大约有25行,每一行都有一些文本和需要从互联网加载的图片。类似于Instagram风格的feed,但这些是每个图片大小约为8k的个人资料图片。
当我基于传入的JSON数据构建表格时,我正在正确地执行所有操作,利用WatchKit内置的图像缓存来减少不必要的网络流量。
应用程序“工作”,并且图像正确显示。但问题在于视图需要10-20秒才能准备好与用户交互。在这10-20秒内,滚动很卡顿,并且按钮在所有图像加载完成之前无法使用。
我希望有一种方法可以在用户向下滚动时延迟加载图片。
我已经尝试过实现分页解决方案,但这也有其缺点,而且并不能完全解决我的原始问题。
如果我只填充文本部分(没有图片),则表格会立即显示并准备好与用户交互。
***更新: Mike Swanson的答案非常详尽,并且解决了我的大部分问题。
我想为任何遇到类似问题的人发布最终代码。具体来说,我想展示如何实现后台派发。
现在我在主线程中暂时将图片设置为占位符以显示活动状态。一旦实际图片加载并传输到手表中,它就会被替换。我还改进了图像缓存密钥,以避免新图像已上传时缺失。
新代码:
当我基于传入的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++
}
ORIGINAL CODE:
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++
}