gpt4 book ai didi

swift - 提示我有关线程安全和 UI 的信息

转载 作者:行者123 更新时间:2023-11-28 08:54:43 27 4
gpt4 key购买 nike

我正在使用 parse.com 实现一个图片发布应用程序。几天前,我的应用程序出现错误,即

2015-10-22 14:36:52.501 bany[2595:874380] * Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array’

但我的阵列没问题。然后我发布了 stackOverFlow,有人告诉我这个问题是我在线程安全和 UI 更新方面做错了。

这是空数组超出边界的后索引 0,有时有效,有时无效

我从 apple reference 中读到线程安全,我发现使用 Mutable 数组是线程不安全的类类型。

这是我的代码。

class MainTVC: UITableViewController {

@IBOutlet weak var categorySegment: UISegmentedControl!

var postsArray : NSMutableArray = NSMutableArray()
var filterdArray : NSMutableArray = NSMutableArray()
var objectTwo : PFObject!

override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)

bringAllDatafromParse()
}

@IBAction func segmentTapped(sender: AnyObject) {

// Empty postArray
postsArray = []

// get post's data by categories
switch categorySegment.selectedSegmentIndex {
case 0 :
bringAllDatafromParse()
case 1 :
bringCategoryDataFromParse(1)

case 2 :
bringCategoryDataFromParse(2)

case 3 :
bringCategoryDataFromParse(3)

default :
bringAllDatafromParse()
}
self.tableView.reloadData()
}


override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()

}

// MARK: - Table view data source

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {

return 1
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

return postsArray.count
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! MainTVCE
let postObjects = self.postsArray.objectAtIndex(indexPath.row) as! PFObject


// IndexPath for comment button on tableView
cell.didRequestToShowComment = { (cell) in
let indexPath = tableView.indexPathForCell(cell)
let objectToSend = self.postsArray[indexPath!.row] as? PFObject
// Show your Comment view controller here, and set object to send here
self.objectTwo = objectToSend!
self.performSegueWithIdentifier("mainToComment", sender: self)
}


// Show sold label or not
cell.soldLabel.hidden = true

if (postObjects.objectForKey("sold") as! Bool) == true {
cell.soldLabel.hidden = false
}


// title Label of post
cell.titleLabel.text = postObjects.objectForKey("titleText") as? String


// nick name of user
if let nickNameExists = postObjects.objectForKey("nickName") as? String {
cell.nickNameLabel.text = nickNameExists
}else {
cell.nickNameLabel.text = postObjects.objectForKey("username") as? String
}


// time label for posts
let dateFormatter:NSDateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "MM /dd /yy"
cell.timeLabel.text = (dateFormatter.stringFromDate(postObjects.createdAt!))


// price label
let price = (postObjects.objectForKey("priceText") as! String)
cell.priceLable.text = " $\(price)"


// main Image for post
let mainImages = postObjects.objectForKey("front_image") as! PFFile
mainImages.getDataInBackgroundWithBlock { (imageData, error) -> Void in
let image = UIImage(data: imageData!)
cell.mainPhoto.image = image
}


//profile picture for user
if let profileImages = (postObjects.objectForKey("profile_picture") as? PFFile){
profileImages.getDataInBackgroundWithBlock { (imageData, error) -> Void in
let image = UIImage(data: imageData!)
cell.profilePhoto.image = image
}
}else{ cell.profilePhoto.image = UIImage(named: "AvatarPlaceholder")
}
circularImage(cell.profilePhoto)



return cell
}



func bringAllDatafromParse() {

//empty postArray
postsArray = []

//bring data from parse
let query = PFQuery(className: "Posts")
query.orderByAscending("createdAt")
query.findObjectsInBackgroundWithBlock { (objects: [PFObject]?, error) -> Void in
if error == nil && objects != nil{
for object : PFObject in objects! {

self.postsArray.addObject(object)
}
let array : Array = self.postsArray.reverseObjectEnumerator().allObjects
self.postsArray = array as! NSMutableArray
}
self.tableView.reloadData()

}

}


func bringCategoryDataFromParse(category : Int) {

let query = PFQuery(className: "Posts")
query.whereKey("category", equalTo: category)
query.orderByAscending("createdAt")
query.findObjectsInBackgroundWithBlock { (objects: [PFObject]?, error) -> Void in
if error == nil && objects != nil{
for object : PFObject in objects! {
self.postsArray.addObject(object)
}
let array : Array = self.postsArray.reverseObjectEnumerator().allObjects

self.postsArray = array as! NSMutableArray
self.tableView.reloadData()
}
}
}


override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// send object to commentViewController
if (segue.identifier == "mainToComment") {
let destViewController : CommentVC = segue.destinationViewController as! CommentVC
destViewController.object = objectTwo
}

// send object to DetailViewController
if (segue.identifier == "mainToDetail") {
let selectedRowIndex = self.tableView.indexPathForSelectedRow
let destViewController : DetailVC = segue.destinationViewController as! DetailVC
destViewController.object = (postsArray[(selectedRowIndex?.row)!] as? PFObject)

}
}

func circularImage(image : UIImageView) {
image.layer.cornerRadius = image.frame.size.width / 2
image.clipsToBounds = true
image.layer.borderColor = UIColor.blackColor().CGColor
image.layer.borderWidth = 1
}



以下是我在查看其他人的代码时对我的代码做错了什么的想法。所以请评论这些是否正确。

  1. 为了线程安全,我应该使用 NSArray 而不是 NSMutableArray。如果我使用 NSArray 可以吗?

  2. 我将使用单独的数据类来检索数据,包括检查 nil 或是否存在值,而不是放入方法“cellForRowAtIndexPath”,该方法“仅”定义单元格以供重用。

如果我这样做,我是否应该从大多数 ViewController 中的数组中检索数据,而不是使用 prepareSegue 方法从具有 retrievingAllData 函数的 mainViewcontroller 发送特定(选定)对象?

  1. 我应该在“cellForRowAtIndexPath”中使用缓存和 dispatch_async是强制性的吗?

4.UI部分,我真是一头雾水。有人可以给小费吗?例如,如何使 UI 显示进度直到数据检索完成?您可以只提示“一个”评论。这对我会有很大帮助。我真的很感激。

请给我建议。

最佳答案

作为一般提示,通过使用 NSArray/NSMutableArray(它可以包含任何类型对象的集合),您将失去很多使用的好处Swift 的 Array 类型(只能包含一种类型的对象)。

Parse findObjectsInBackgroundWithBlock 方法已经返回一个 PFObjects 数组,因此没有任何理由切换到使用 NSArray。

顾名思义,findObjectsInBackgroundWithBlock 正在后台线程上执行 block (因为它可能需要一段时间才能完成,并且您不希望它锁定您的 UI 更新所在的主线程正在执行)。

调用 self.tableView.reloadData() 会启动更新您的 UI 的事件链,因此应该在主线程上调用它。您可以使用 GCD 函数 dispatch_async 轻松完成此操作。这是显示这两种更改的一种方法的更新:

query.findObjectsInBackgroundWithBlock { (objects:[PFObject]?, error:NSError?) -> Void in

// unwrap the optional array of PFObjects
if let objects = objects {

// reverse your objects
self.postsArray = objects.reverse()

// trigger update to table on the main thread
dispatch_async(dispatch_get_main_queue(),{
self.tableView.reloadData()
})
}
// if objects is nil that means there was an some error
else {
// unwrap the optional error
if let error = error {
// do something about the error - present feedback etc
}
}
}

如您所见,直接使用对象数组并使用reverse 方法可以使代码更加清晰。

您还使用了 ! 来强制解包一个可选的,这不是一个养成的好习惯。可选项是 Swift 的一个非常核心的部分,确保你全神贯注于它们是有意义的,你的代码会更安全并且不太可能崩溃 :) http://roadfiresoftware.com/2014/12/wrap-your-head-around-optionals-in-swift/

子类化 PFObject

这是一个完全可选的步骤,但使用解析 API 最有趣的事情之一是能够子类化 PFObject。因此,不必总是像这样访问您的对象属性:

postObjects.objectForKey("titleText") as? String

你可以这样做:

postObjects.titleText

它需要一些设置,在 this answer 中针对 swift 进行了描述。也在parse.com docs .

希望对您有所帮助!

关于swift - 提示我有关线程安全和 UI 的信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33384637/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com