如何按升序下载一行中的名称和图像
How to download name and images on one row in ascending order
我已经对此进行了研究,但似乎没有任何效果。我正在尝试构建一个食谱应用程序,但菜品图像和菜品名称(开胃菜)未按顺序下载。我该怎么做?
代码:
class Appetizers: UITableViewController {
var valueToPass: String!
var valuePassed: String!
var appetizer = [String]()
var images = [UIImage]()
func refresh() {
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
})
}
override func viewDidLoad() {
super.viewDidLoad()
// Parse - class - column
let query = PFQuery(className: "Appetizers")
query.orderByAscending("appetizer")
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if error == nil {
if let objects = objects {
for object in objects {
let load = object.objectForKey("appetizer") as! String
self.appetizer.append(load)
let imageFile = object["imageFiles"] as! PFFile
imageFile.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in
if error != nil {
print(error)
} else {
if let data = imageData {
self.images.append(UIImage(data: data)!)
self.tableView.reloadData()
}
}
})
self.tableView.reloadData()
}
}
} else {
print("Error: \(error!) \(error!.userInfo)")
}
}
sleep(1)
refresh()
}
override func viewWillAppear(animated: Bool) {
self.tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return appetizer.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
cell.textLabel?.text = appetizer[indexPath.row]
// add image to table
if images.count > indexPath.row {
cell.imageView?.image = images[indexPath.row]
}
return cell
}
// when user taps on cell ...
func getCellLabel () {
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRowAtIndexPath(indexPath) as UITableViewCell!
valueToPass = currentCell.textLabel!.text
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
getCellLabel()
self.performSegueWithIdentifier("0", sender: self)
}
}
执行异步查询时,您无法保证它们完成的顺序。因此,两个独立数组的概念,一个是字符串数组,另一个是图像数组,总是有问题的。
例如,您可以将 images
替换为由开胃菜名称索引的字典,这样他们完成的顺序就无关紧要了。
var appetizer = [String]()
var images = [String: UIImage]()
因此,它可能看起来像:
override func viewDidLoad() {
super.viewDidLoad()
let query = PFQuery(className: "Appetizers")
query.orderByAscending("appetizer")
query.findObjectsInBackgroundWithBlock { objects, error in
guard error == nil, let objects = objects else {
print(error)
return
}
for (index, object) in objects.enumerate() {
let appetizerName = object.objectForKey("appetizer") as! String
self.appetizer.append(appetizerName)
let imageFile = object["imageFiles"] as! PFFile
imageFile.getDataInBackgroundWithBlock { imageData, error in
guard error == nil, let data = imageData else {
print(error)
return
}
// when the image comes in, asynchronously update only that one row
self.images[appetizerName] = UIImage(data: data)
self.tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: index, inSection: 0)], withRowAnimation: .Fade)
}
}
// reload the table only once, after all of the `appetizer` entries are created (but likely before the images come in)
self.tableView.reloadData()
}
}
和
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
let name = appetizer[indexPath.row]
cell.textLabel?.text = name
cell.imageView?.image = images[name]
return cell
}
或者您可以将这两个单独的属性替换为一个自定义对象数组(例如,一个 Appetizer
对象同时具有 name
属性 和 image
属性).
但是无论你这样做,你都想确定你不是在处理两个单独的数组。
顺便说一句,但是如果您有很多行,加载所有图像的过程可能会出现问题。此代码使用 "eager" 图像加载(无论当前是否需要,都加载它们)。问题是图像是相对较大的资产(与字符串值相比),您可能 运行 遇到内存问题、网络带宽问题等
人们通常喜欢使用 "lazy" 加载(例如,让 cellForRowAtIndexPath
仅在需要时请求图像。例如,假设您有 200 行,其中只有 12 行一次可见点。你不应该请求 200 张图像,而应该只请求 12 张可见图像。如果你从 viewDidLoad
中取出图像检索,而是让 cellForRowAtIndexPath
一次请求一张,您将拥有更好的网络性能和更低要求的内存特性。
如果您要像代码当前那样以某种结构保存图像,至少要确保在收到内存警告通知后清除这些图像(并且,显然,优雅地处理重新 -根据需要以 JIT 方式请求它们)。
我发现了我的 table 没有 sleep() 无法加载的问题......
我在街区外有 'self.tableView.reloadData()'。
Rob 帮了大忙 :)
我已经对此进行了研究,但似乎没有任何效果。我正在尝试构建一个食谱应用程序,但菜品图像和菜品名称(开胃菜)未按顺序下载。我该怎么做?
代码:
class Appetizers: UITableViewController {
var valueToPass: String!
var valuePassed: String!
var appetizer = [String]()
var images = [UIImage]()
func refresh() {
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
})
}
override func viewDidLoad() {
super.viewDidLoad()
// Parse - class - column
let query = PFQuery(className: "Appetizers")
query.orderByAscending("appetizer")
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if error == nil {
if let objects = objects {
for object in objects {
let load = object.objectForKey("appetizer") as! String
self.appetizer.append(load)
let imageFile = object["imageFiles"] as! PFFile
imageFile.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in
if error != nil {
print(error)
} else {
if let data = imageData {
self.images.append(UIImage(data: data)!)
self.tableView.reloadData()
}
}
})
self.tableView.reloadData()
}
}
} else {
print("Error: \(error!) \(error!.userInfo)")
}
}
sleep(1)
refresh()
}
override func viewWillAppear(animated: Bool) {
self.tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return appetizer.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
cell.textLabel?.text = appetizer[indexPath.row]
// add image to table
if images.count > indexPath.row {
cell.imageView?.image = images[indexPath.row]
}
return cell
}
// when user taps on cell ...
func getCellLabel () {
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRowAtIndexPath(indexPath) as UITableViewCell!
valueToPass = currentCell.textLabel!.text
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
getCellLabel()
self.performSegueWithIdentifier("0", sender: self)
}
}
执行异步查询时,您无法保证它们完成的顺序。因此,两个独立数组的概念,一个是字符串数组,另一个是图像数组,总是有问题的。
例如,您可以将 images
替换为由开胃菜名称索引的字典,这样他们完成的顺序就无关紧要了。
var appetizer = [String]()
var images = [String: UIImage]()
因此,它可能看起来像:
override func viewDidLoad() {
super.viewDidLoad()
let query = PFQuery(className: "Appetizers")
query.orderByAscending("appetizer")
query.findObjectsInBackgroundWithBlock { objects, error in
guard error == nil, let objects = objects else {
print(error)
return
}
for (index, object) in objects.enumerate() {
let appetizerName = object.objectForKey("appetizer") as! String
self.appetizer.append(appetizerName)
let imageFile = object["imageFiles"] as! PFFile
imageFile.getDataInBackgroundWithBlock { imageData, error in
guard error == nil, let data = imageData else {
print(error)
return
}
// when the image comes in, asynchronously update only that one row
self.images[appetizerName] = UIImage(data: data)
self.tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: index, inSection: 0)], withRowAnimation: .Fade)
}
}
// reload the table only once, after all of the `appetizer` entries are created (but likely before the images come in)
self.tableView.reloadData()
}
}
和
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
let name = appetizer[indexPath.row]
cell.textLabel?.text = name
cell.imageView?.image = images[name]
return cell
}
或者您可以将这两个单独的属性替换为一个自定义对象数组(例如,一个 Appetizer
对象同时具有 name
属性 和 image
属性).
但是无论你这样做,你都想确定你不是在处理两个单独的数组。
顺便说一句,但是如果您有很多行,加载所有图像的过程可能会出现问题。此代码使用 "eager" 图像加载(无论当前是否需要,都加载它们)。问题是图像是相对较大的资产(与字符串值相比),您可能 运行 遇到内存问题、网络带宽问题等
人们通常喜欢使用 "lazy" 加载(例如,让 cellForRowAtIndexPath
仅在需要时请求图像。例如,假设您有 200 行,其中只有 12 行一次可见点。你不应该请求 200 张图像,而应该只请求 12 张可见图像。如果你从 viewDidLoad
中取出图像检索,而是让 cellForRowAtIndexPath
一次请求一张,您将拥有更好的网络性能和更低要求的内存特性。
如果您要像代码当前那样以某种结构保存图像,至少要确保在收到内存警告通知后清除这些图像(并且,显然,优雅地处理重新 -根据需要以 JIT 方式请求它们)。
我发现了我的 table 没有 sleep() 无法加载的问题...... 我在街区外有 'self.tableView.reloadData()'。 Rob 帮了大忙 :)