(Swift)Ex_Bad_Access in heightForRowAtIndexPath with Variable Row Height

时间:2014-06-19 01:16:40

标签: ios uitableview swift

首先,错误:

 > Assertion failure in 
-[UITableView _dequeueReusableViewOfType:withIdentifier:], 
/SourceCache/UIKit_Sim/UIKit-3232.3/UITableView.m:5978
    2014-06-18 17:49:51.887 Twitter App[21909:583896] \

***Terminating app due to uncaught exception 'NSInternalInconsistencyException',

 reason: 'invalid nib registered for identifier (CustomTimelineCell) - nib must contain exactly one top level object which must be a UITableViewCell instance'**

其次,背景:TableViewController从Twitter中提取时间线,解析它,更新使用动态原型自定义单元格的tableView。通过创建具有该推文属性的虚拟单元格然后返回高度,在heightForRowAtIndexPath中计算每个单元格的高度。一切正常,但是当离开视图并返回按钮时,视图会重复该过程并崩溃。

相关守则:

var tweetsArray:NSArray = NSArray()
var accountStore:ACAccountStore = ACAccountStore()
var account:ACAccount = ACAccount()
var profileImages:NSMutableDictionary = NSMutableDictionary()

let identifier:NSString = "CustomTimelineCell"

//viewWillAppear simply requests authorization and calls the following functions to do the work

func reloadTimeline() {

    requestAuthorization()

    var url: NSURL = NSURL.URLWithString("https://api.twitter.com/1.1/statuses/home_timeline.json")

    var params: NSDictionary = ["trim_user" : "false", "count" : "200"]

    var request: SLRequest = SLRequest(forServiceType: SLServiceTypeTwitter, requestMethod: SLRequestMethod.GET, URL: url, parameters: params)

    request.account = account

    // Execute the Request

    let requestHandler: SLRequestHandler = {responseData, urlResponse, error in

        if responseData {
            if urlResponse.statusCode >= 200 && urlResponse.statusCode < 300 {

                var error: NSError? = NSError()

                let feedData:NSArray? = NSJSONSerialization.JSONObjectWithData(responseData, options: NSJSONReadingOptions.AllowFragments, error: &error) as? NSArray

                if feedData {
                    self.updateFeed(feedData!)
                    //println("Timeline Response: \(self.tweetsArray)")
                }
            }
            else {
                println("Response Status Code: \(urlResponse.statusCode)")
            }

        }
        if error {
            println(error.localizedDescription)
        }
        UIApplication.sharedApplication().networkActivityIndicatorVisible = false
    }

    request.performRequestWithHandler(requestHandler)
    UIApplication.sharedApplication().networkActivityIndicatorVisible = true

}

func updateFeed(feedData: NSArray) {
    tweetsArray = feedData
    self.tableView.layoutIfNeeded()
    tableView.reloadData()
    self.stopRefresh()

}

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

    var cell : CustomTimelineCell = tableView!.dequeueReusableCellWithIdentifier(identifier, forIndexPath: indexPath!) as CustomTimelineCell

    let currentTweet:NSDictionary = tweetsArray.objectAtIndex(indexPath.row) as NSDictionary

    let currentUser:NSDictionary = currentTweet.objectForKey("user") as NSDictionary

    cell.username.text = currentUser.objectForKey("name") as NSString!
    cell.tweetText.text = currentTweet.objectForKey("text") as NSString!
    cell.userImage.image = UIImage(named: "bird_twitter.png")

    // Adds and Configures Gesture Recognizer for Profile Image (uses segue made from unused IB gesture recognizer)
    if !cell.userImage.gestureRecognizers {

        cell.userImage.userInteractionEnabled = true

        var imageTapRecognizer:UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "profileImageTap")
        imageTapRecognizer.numberOfTapsRequired = 1
        imageTapRecognizer.numberOfTouchesRequired = 1
        cell.userImage.addGestureRecognizer(imageTapRecognizer)

    }

    // May or may not be necessary, but including constraint resizing restrictions
    cell.setTranslatesAutoresizingMaskIntoConstraints(true)
    cell.username.setTranslatesAutoresizingMaskIntoConstraints(false)
    cell.tweetText.setTranslatesAutoresizingMaskIntoConstraints(false)
    cell.userImage.setTranslatesAutoresizingMaskIntoConstraints(false)

    let imageDimension:CGSize = CGSize(width: 48, height: 48)
    cell.sizeThatFits(imageDimension)

    var usernameString = currentUser.objectForKey("name") as NSString!

    if profileImages.objectForKey(usernameString) {
        cell.userImage.image = profileImages.objectForKey(usernameString) as UIImage!
    }
    else {

        // Creates Concurrent Queue for Image Fetching
        var concurrentQueue:dispatch_queue_t = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

        // Asynchronously get URL String and convert to NSURL
        dispatch_async(concurrentQueue, {

            var imageURLString:NSString = currentUser.objectForKey("profile_image_url") as NSString!

            var imageURL = NSURL(string: imageURLString)

            // Synchronously download image data and save to profileImages array (1 by 1)
            dispatch_sync(concurrentQueue, {
                var imageData:NSData = NSData(contentsOfURL: imageURL)

                self.profileImages.setObject((UIImage(data:imageData)), forKey: usernameString)
                })
            // In Main Queue, set the profileImage for each cell from newly populated array
            dispatch_sync(dispatch_get_main_queue(), {
                cell.userImage.image = self.profileImages.objectForKey(usernameString) as UIImage!
                })
            })
    }

    return cell
}

应用程序总是在此函数中崩溃(我不知道在dequeueReusableCell行,Swift如何处理nil对象,是否一切都得到了适当处理。

override func tableView(tableView: UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat {

    var currentTweet:NSDictionary = tweetsArray.objectAtIndex(indexPath.row) as NSDictionary

    var currentUser:NSDictionary = currentTweet.objectForKey("user") as NSDictionary
    var usernameString = currentUser.objectForKey("name") as NSString!
    var tweetTextString = currentTweet.objectForKey("text") as NSString!

    var prototypeCell = tableView!.dequeueReusableCellWithIdentifier(identifier) as? CustomTimelineCell

    if let customCell = prototypeCell {

        customCell.username.text = usernameString
        customCell.tweetText.text = tweetTextString
        customCell.userImage.image = UIImage(named: "bird_twitter.png")

        var size:CGSize = customCell.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)

        return size.height+1
    }
    else {

        var customCell:CustomTimelineCell = CustomTimelineCell(style: UITableViewCellStyle.Default, reuseIdentifier: "CustomTimelineCell")
        customCell.username.text = usernameString
        customCell.tweetText.text = tweetTextString
        customCell.userImage.image = UIImage(named: "bird_twitter.png")

        var size:CGSize = customCell.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)

        return size.height+1
    }
}

我通过StackOverflow上下搜索与其相关的每个错误以及尝试修复它时弹出的所有内容,但没有任何效果。我不知道是不是因为Swift处理事情的方式,但我相信问题在于返回视图时是否将单元格出列,或者在我离开之前某些连接没有关闭/回。有什么想法吗?

编辑:一些可能相关的新信息:在最初加载后滚动浏览tableView时,每个单元格都会调用-heightForRowAtIndexPath两次,我无法理解原因。此外,当从另一个视图返回到tableView时,当它重新加载时,它会为前几个单元格调用-heightforRowAtIndexPath两次,但对其余单元格只调用一次(0,1,0,1,2,3 ...)。这与exc_bad_access崩溃有关吗?

0 个答案:

没有答案