在UITableView Swift

时间:2015-06-29 01:08:33

标签: ios swift uitableview parse-platform refactoring

我有一个相当长的cellForRowAtIndexPath功能。我使用解析作为我的后端并且有很多事情要做。我想提取很多这些条件并将它们放在自己的函数中。特别是PFUser查询,但不幸的是我不知道最好的方法,因为我不知道如何在我想写的那些函数中访问每个单元格的元素。

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

    let cell = tableView.dequeueReusableCellWithIdentifier("PostCells", forIndexPath: indexPath) as! NewsFeedTableCellTableViewCell

    // Configure the cell...

    // A drive is a post
    let drive: PFObject = self.timelineData[indexPath.row] as PFObject
    var driverId = drive.objectForKey("driver")!.objectId!
    var currentUserObjectId = PFUser.currentUser()!.objectId
    if(driverId != currentUserObjectId){
        cell.requestButton.layer.borderWidth = 1
        cell.requestButton.titleLabel!.font = UIFont.systemFontOfSize(11)
        cell.requestButton.tintColor = UIColor.orangeColor()
        cell.requestButton.layer.borderColor = UIColor.orangeColor().CGColor
        cell.requestButton.setTitle("REQUEST", forState: UIControlState.Normal)

    }
    else {

        cell.requestButton.layer.borderWidth = 1
        cell.requestButton.titleLabel!.font = UIFont.systemFontOfSize(11)
        cell.requestButton.tintColor = UIColor.grayColor()
        cell.requestButton.layer.borderColor = UIColor.lightGrayColor().CGColor
        cell.requestButton.setTitle("REQUEST", forState: UIControlState.Normal)
        cell.requestButton.enabled = false

    }


    // Setting up the attributes of the cell for the news feed
    cell.driveTitleTextField.text = drive.objectForKey("title") as! String
    cell.wayTextField.text = drive.objectForKey("way") as! String

    var departureDate = NSDate()
    departureDate = drive.objectForKey("departureDate") as! NSDate
    var dateFormat = NSDateFormatter()
    dateFormat.dateFormat = "M/dd hh:mm a"
    cell.departureDateTextField.text = dateFormat.stringFromDate(departureDate)

    if((drive.objectForKey("way")!.isEqualToString("Two Way")))
    {
        var returnDate = NSDate()
        returnDate = drive.objectForKey("returnDate") as! NSDate
        cell.returningDateTextField.text = dateFormat.stringFromDate(returnDate)
    }
    else if((drive.objectForKey("way")!.isEqualToString("One Way")))
    {
        cell.returningDateTextField.enabled = false
        cell.returningDateTextField.userInteractionEnabled = false
        cell.returningDateTextField.hidden = true
        cell.returningLabel.hidden = true
    }

    var seatNumber = NSNumber()
    seatNumber = drive.objectForKey("seatNumber") as! NSInteger
    var numberFormat = NSNumberFormatter()
    numberFormat.stringFromNumber(seatNumber)
    cell.seatNumberTextField.text = numberFormat.stringFromNumber(seatNumber)


    // this is a PFUser query so we can get the users image and name and email from the User class 
    var findDrive = PFUser.query()
    var objectId: AnyObject? = drive.objectForKey("driver")!.objectId!
    findDrive?.whereKey("objectId", equalTo: objectId!)
    findDrive?.findObjectsInBackgroundWithBlock{
        (objects:[AnyObject]?, error:NSError?)->Void in
        if (error == nil){
            if let actualObjects = objects {
                let possibleUser = (actualObjects as NSArray).lastObject as? PFUser
                if let user = possibleUser {
                    cell.userProfileNameLabel.text = user["fullName"] as? String
                    cell.userEmailLabel.text = user["username"] as? String

                    //Profile Image
                    cell.profileImage.alpha = 0
                    if let profileImage = user["profilePicture"] as? PFFile {
                        profileImage.getDataInBackgroundWithBlock{
                            (imageData:NSData? , error:NSError?)-> Void in

                            if(error == nil) {
                                if imageData != nil{
                                    let image:UIImage = UIImage (data: imageData!)!
                                    cell.profileImage.image = image
                                }
                            }
                        }

                    }

                    UIView.animateWithDuration(0.5, animations: {
                        cell.driveTitleTextField.alpha = 1
                        cell.wayTextField.alpha = 1
                        cell.profileImage.alpha = 1
                        cell.userProfileNameLabel.alpha = 1
                        cell.userEmailLabel.alpha = 1
                        cell.seatNumberTextField.alpha = 1
                        cell.returningDateTextField.alpha = 1
                        cell.departureDateTextField.alpha = 1

                    })

                }
            }

        }
    }
    return cell
}

编辑1

我想出了一种重构我想要批评的代码的方法!

1。我提取了很多单元格配置并将它们放入函数中,一个用于单元格上的按钮,另一个用于解析所有数据。

func configureDataTableViewCell(cell:NewsFeedTableCellTableViewCell, drive: PFObject)
{
    cell.driveTitleTextField.text = drive.objectForKey("title") as! String
    cell.wayTextField.text = drive.objectForKey("way") as! String
    cell.userEmailLabel.text = drive.objectForKey("username") as? String
    cell.userProfileNameLabel.text = drive.objectForKey("name") as? String

    var departureDate = NSDate()
    departureDate = drive.objectForKey("departureDate") as! NSDate
    var dateFormat = NSDateFormatter()
    dateFormat.dateFormat = "M/dd hh:mm a"
    cell.departureDateTextField.text = dateFormat.stringFromDate(departureDate)

    if((drive.objectForKey("way")!.isEqualToString("Two Way")))
    {
        var returnDate = NSDate()
        returnDate = drive.objectForKey("returnDate") as! NSDate
        cell.returningDateTextField.text = dateFormat.stringFromDate(returnDate)
    }
    else if((drive.objectForKey("way")!.isEqualToString("One Way")))
    {
        cell.returningDateTextField.enabled = false
        cell.returningDateTextField.userInteractionEnabled = false
        cell.returningDateTextField.hidden = true
        cell.returningLabel.hidden = true
    }

    var seatNumber = NSNumber()
    seatNumber = drive.objectForKey("seatNumber") as! NSInteger
    var numberFormat = NSNumberFormatter()
    numberFormat.stringFromNumber(seatNumber)
    cell.seatNumberTextField.text = numberFormat.stringFromNumber(seatNumber)


}

func configureButtonTableViewCell(cell:NewsFeedTableCellTableViewCell, userID: String)
{
    var currentUserObjectId = PFUser.currentUser()!.objectId
    if(userID != currentUserObjectId){
        cell.requestButton.layer.borderWidth = 1
        cell.requestButton.titleLabel!.font = UIFont.systemFontOfSize(11)
        cell.requestButton.tintColor = UIColor.orangeColor()
        cell.requestButton.layer.borderColor = UIColor.orangeColor().CGColor
        cell.requestButton.setTitle("REQUEST", forState: UIControlState.Normal)
        println("orange")
    }
    else {

        cell.requestButton.layer.borderWidth = 1
        cell.requestButton.titleLabel!.font = UIFont.systemFontOfSize(11)
        cell.requestButton.tintColor = UIColor.grayColor()
        cell.requestButton.layer.borderColor = UIColor.lightGrayColor().CGColor
        cell.requestButton.setTitle("REQUEST", forState: UIControlState.Normal)
        cell.requestButton.enabled = false
        println("gray")
    }

}

2。然后我将步骤1中的功能传入我的cellForRowIndexPath

    // A drive is a post
    let drive: PFObject = self.timelineData[indexPath.row] as PFObject
    var driverId : String = drive.objectForKey("driver")!.objectId!!
    configureButtonTableViewCell(cell, userID: driverId)
    configureDataTableViewCell(cell, drive: drive)

3. 我将所有PFUser数据存储到我的对象中,而不是查询用户类。因此,我在保存帖子时会收到PFUser.currentUser()用户名,全名和个人资料照片。

我的加载数据已被修改。我将所有配置文件图片存储在自己的数组中。

func loadData(){


    var findItemData:PFQuery = PFQuery(className:"Posts")

    findItemData.addDescendingOrder("createdAt")

    findItemData.findObjectsInBackgroundWithBlock{
        (objects:[AnyObject]? , error:NSError?) -> Void in
            if error == nil
            {
                self.timelineData.removeAll(keepCapacity: false)
                self.profilePictures.removeAll(keepCapacity: false)
                self.timelineData = objects as! [PFObject]
                for object in objects! {

                    self.profilePictures.append(object.objectForKey("profilePicture") as! PFFile)


                }

                self.newsFeedTableView.reloadData()


            }

    }
}

最后,这是我更新的cellForRowIndexPath

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

    var cell = tableView.dequeueReusableCellWithIdentifier("PostCells", forIndexPath: indexPath) as! NewsFeedTableCellTableViewCell

    // Configure the cell...

    // A drive is a post
    let drive: PFObject = self.timelineData[indexPath.row] as PFObject
    var driverId : String = drive.objectForKey("driver")!.objectId!!
    configureButtonTableViewCell(cell, userID: driverId)
    configureDataTableViewCell(cell, drive: drive)
    println(PFUser.currentUser()?.objectForKey("username"))


    if let profileImage = drive["profilePicture"] as? PFFile {
        profileImage.getDataInBackgroundWithBlock{
            (imageData:NSData? , error:NSError?)-> Void in

            if(error == nil) {
                if imageData != nil{
                    let image:UIImage = UIImage (data: imageData!)!
                    cell.profileImage.image = image
                }
            }
        }

    }


    return cell
}

让我知道你们的想法,我想让我的代码更具可读性,快速性和内存效率。

2 个答案:

答案 0 :(得分:4)

你不应该在cellForRow中做任何沉重的模型。 您目前要做的事情将大大减慢您的用户界面。

在大多数情况下,您需要设置模型对象,并在进入cellForRow之前准备就绪。

这意味着在viewDidLoad中的某处执行Parse查询,将这些结果保存在数组中,当需要这样做时,将它们应用于cellForRow中的单元格。这样,当用户滚动时,不会为每个进入视图的新单元调度新查询。它已经可用了。

除此之外,如果您在获取这些项目后需要对这些项目进行任何更改,您可以这样做,即使在用户滚动时也保持不变。

答案 1 :(得分:0)

重构,因此您可以使用某些数据类型或实例变量组作为视图模型。避免在cellForRowAtIndexPath中进行异步调用以改变单元格。相反,您的数据访问方法会改变或重新创建视图模型,并在回调结束时将dispatch_async更改为主队列。给它一个闭包,告诉你的表视图reloadData以及你需要为视图做的其他事情以显示新数据。

这是一个描述我的意思的小伪代码:

func loadData() {
    parseQueryWithCallback() { data in
        self.viewModel = doWhateverTransformsAreNeeded(data)
        dispatch_async(dispatch_get_main_queue(), self.tableView.reloadData)
    }
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) {
    let cell = dequeue(...)
    cell.thingOne = self.viewModel.things[indexPath.row].thingOne
    cell.thingTwo = self.viewModel.things[indexPath.row].thingTwo
    return cell
}