0

I have an app with about 30 active users and 500+ registered users and this issue is only happening with one person who is on 9.2 using an iPhone 6.

I can see from crash reports she's had over 60 crashes and she has said that the problem is OK sometimes and not others.

I have the same test device here and no issue is happening.

I can't get much out of the crash report details from fabric but the crash is happening at the following method and the app is crashing at the final else of this method, I can tell from her description of the problem:

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
    {
        let bounds = UIScreen.mainScreen().bounds
        var screenWidth = bounds.size.width
        let screenHeight = bounds.size.height
        if indexPath.row == 0 {
            let font = UIFont(name: "Helvetica Neue", size: 17.0)
            let heightCalc = heightForView(self.postDescription!, font: font!, width: screenWidth - 32)
            if self.photoWidth != nil{

                let imageAspectRatio = self.photoWidth!/self.photoHeight!
                var imageViewFrameHeight = screenWidth/imageAspectRatio
                if self.portBool {
                    if imageViewFrameHeight > (screenHeight - 64) {
                        screenWidth = screenWidth * 0.60
                        imageViewFrameHeight = imageViewFrameHeight * 0.60
                    }
                }

                return imageViewFrameHeight + 136 + heightCalc + 26
                //return 557
            }
            else{
                return 136 + heightCalc + 30
            }
        }
        else if indexPath.row == 1 {
            return 50.0
        }
        else if indexPath.row == 2{
            return 40.0
        }
        else{

            if self.commentsDetailed != nil && self.commentsDetailed!.count >= (indexPath.row - 3)
            {
                let commentsDetailed = self.commentsDetailed![indexPath.row-3]
                let font = UIFont(name: "Helvetica Neue", size: 14.0)

                let heightCalc = heightForView(commentsDetailed.comment!, font: font!, width: screenWidth - 51)

                if commentsDetailed.authorId == Prefs.userId.description {
                    return 45 + heightCalc + 40 + 30
                    //return 131.5
                }
                else{
                    return 45 + heightCalc + 40
                    //return 101.5
                }

            }
            else {
                return 80.0
            }

        }
    }

For those wondering, I need to calculate the height to avoid a jittery scroll which was happening when I was using the table view automatic dimension. So I just need to solve the issue within here and not switch approach.

Some info from crashlytics:

EXC_BREAKPOINT

Thread : Crashed: Thread
0  ProjectName                   0x10008a64c specialized NewFeedDetailedController.tableView(UITableView, heightForRowAtIndexPath : NSIndexPath) -> CGFloat (NewFeedDetailedController.swift)
1  ProjectName                   0x100085258 @objc NewFeedDetailedController.tableView(UITableView, heightForRowAtIndexPath : NSIndexPath) -> CGFloat (NewFeedDetailedController.swift)
2  UIKit                          0x187683638 __66-[UISectionRowData refreshWithSection:tableView:tableViewRowData:]_block_invoke + 396
3  UIKit                          0x187641818 -[UISectionRowData refreshWithSection:tableView:tableViewRowData:] + 3948
4  UIKit                          0x1876407d4 -[UITableViewRowData rectForFooterInSection:heightCanBeGuessed:] + 412
5  UIKit                          0x187640590 -[UITableViewRowData heightForTable] + 64
6  UIKit                          0x18764039c -[UITableView _updateContentSize] + 220
7  UIKit                          0x1878a6f60 -[UITableView _rebuildGeometry] + 44
8  UIKit                          0x1876462c8 -[UITableView didMoveToWindow] + 144
9  UIKit                          0x18755705c -[UIView(Internal) _didMoveFromWindow:toWindow:] + 1496
10 UIKit                          0x18757c568 -[UIScrollView _didMoveFromWindow:toWindow:] + 92
11 UIKit                          0x187556d7c -[UIView(Internal) _didMoveFromWindow:toWindow:] + 760
12 UIKit                          0x187556310 __45-[UIView(Hierarchy) _postMovedFromSuperview:]_block_invoke + 152
13 Foundation                     0x183189500 -[NSISEngine withBehaviors:performModifications:] + 168
14 UIKit                          0x187556194 -[UIView(Hierarchy) _postMovedFromSuperview:] + 532
15 UIKit                          0x187563b80 -[UIView(Internal) _addSubview:positioned:relativeTo:] + 1784
16 UIKit                          0x187755600 -[_UIParallaxDimmingView didMoveToWindow] + 180
17 UIKit                          0x18755705c -[UIView(Internal) _didMoveFromWindow:toWindow:] + 1496
18 UIKit                          0x187556d7c -[UIView(Internal) _didMoveFromWindow:toWindow:] + 760
19 UIKit                          0x187556310 __45-[UIView(Hierarchy) _postMovedFromSuperview:]_block_invoke + 152
20 Foundation                     0x183189500 -[NSISEngine withBehaviors:performModifications:] + 168
21 UIKit                          0x187556194 -[UIView(Hierarchy) _postMovedFromSuperview:] + 532
22 UIKit                          0x187563b80 -[UIView(Internal) _addSubview:positioned:relativeTo:] + 1784
23 UIKit                          0x1877f5db4 __53-[_UINavigationParallaxTransition animateTransition:]_block_invoke_2 + 1656
24 UIKit                          0x18756a964 +[UIView(Animation) performWithoutAnimation:] + 80
25 UIKit                          0x187755118 __53-[_UINavigationParallaxTransition animateTransition:]_block_invoke + 260
26 UIKit                          0x187870840 +[UIView(Internal) _performBlockDelayingTriggeringResponderEvents:] + 220
27 UIKit                          0x187754c90 -[_UINavigationParallaxTransition animateTransition:] + 1060
28 UIKit                          0x18770e6a0 -[UINavigationController _startCustomTransition:] + 3544
29 UIKit                          0x18761a9b8 -[UINavigationController _startDeferredTransitionIfNeeded:] + 688
30 UIKit                          0x18761a694 -[UINavigationController __viewWillLayoutSubviews] + 60
31 UIKit                          0x18761a5fc -[UILayoutContainerView layoutSubviews] + 208
32 UIKit                          0x187557778 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 656
33 QuartzCore                     0x184f66b2c -[CALayer layoutSublayers] + 148
34 QuartzCore                     0x184f61738 CA::Layer::layout_if_needed(CA::Transaction*) + 292
35 QuartzCore                     0x184f615f8 CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 32
36 QuartzCore                     0x184f60c94 CA::Context::commit_transaction(CA::Transaction*) + 252
37 QuartzCore                     0x184f609dc CA::Transaction::commit() + 512
38 UIKit                          0x18754dc78 _afterCACommitHandler + 180
39 CoreFoundation                 0x182820588 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 32
40 CoreFoundation                 0x18281e32c __CFRunLoopDoObservers + 372
41 CoreFoundation                 0x18281e75c __CFRunLoopRun + 928
42 CoreFoundation                 0x18274d680 CFRunLoopRunSpecific + 384
43 GraphicsServices               0x183c5c088 GSEventRunModal + 180
44 UIKit                          0x1875c4d90 UIApplicationMain + 204
45 ProjectName                   0x1001663b0 main (AppDelegate.swift:21)
46 libdyld.dylib                  0x1822ee8b8 start + 4 

And the heightForView func:

func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat{
        let label:UILabel = UILabel(frame: CGRectMake(0, 0, width, CGFloat.max))
        label.numberOfLines = 0
        label.lineBreakMode = NSLineBreakMode.ByWordWrapping
        label.font = font
        label.text = text

        label.sizeToFit()
        return label.frame.height
    }

Updated Code with checks for nil, still crashing for the user:

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
    {
        let bounds = UIScreen.mainScreen().bounds
        var screenWidth = bounds.size.width
        let screenHeight = bounds.size.height
        if indexPath.row == 0 {
            CLSLogv("crashing in indexPath.Row = 0 %@", getVaList(["returning 50.0 here"]))

            let font = UIFont(name: "Helvetica Neue", size: 17.0)

            if let description = self.postDescription {
                let heightCalc = heightForView(description, font: font!, width: screenWidth - 32)
                if self.photoWidth != nil && self.photoHeight != nil {
                    CLSLogv("crashing in indexPath.Row = 0 %@", getVaList(["inside photowidth is not nil"]))
                    let imageAspectRatio = self.photoWidth!/self.photoHeight!
                    var imageViewFrameHeight = screenWidth/imageAspectRatio
                    if self.portBool {
                        if imageViewFrameHeight > (screenHeight - 64) {
                            screenWidth = screenWidth * 0.60
                            imageViewFrameHeight = imageViewFrameHeight * 0.60
                        }
                    }

                    return imageViewFrameHeight + 136.0 + heightCalc + 26.0
                    //return 557
                }
                else{
                    CLSLogv("crashing in indexPath.Row = 0 %@", getVaList(["when photowidth is nil"]))
                    return 136.0 + heightCalc + 30.0
                }
            }
            else{
                CLSLogv("crashing in indexPath.Row = 0 %@", getVaList(["unable to unwrap self.postDescription"]))
                if self.photoWidth != nil && self.photoHeight != nil {
                    let imageAspectRatio = self.photoWidth!/self.photoHeight!
                    var imageViewFrameHeight = screenWidth/imageAspectRatio
                    if self.portBool {
                        if imageViewFrameHeight > (screenHeight - 64) {
                            screenWidth = screenWidth * 0.60
                            imageViewFrameHeight = imageViewFrameHeight * 0.60
                        }
                    }

                    return imageViewFrameHeight + 136.0 + 26.0
                }
                else{
                    return 136.0 + 30.0
                }
            }
        }
        else if indexPath.row == 1 {
             CLSLogv("crashing in indexPath.Row = 1 %@", getVaList(["returning 50.0 here"]))
            return 50.0
        }
        else if indexPath.row == 2 {
            CLSLogv("crashing in indexPath.Row = 2 %@", getVaList(["returning 40.0 here"]))
            return 40.0
        }
        else{

            if self.commentsDetailed != nil && self.commentsDetailed!.count > (indexPath.row - 3)
            {

                if let commentsDetailed = self.commentsDetailed?[indexPath.row-3]{


                    let font = UIFont(name: "Helvetica Neue", size: 14.0)
                    if let comment = commentsDetailed.comment{
                        let heightCalc = heightForView(comment, font: font!, width: screenWidth - 51)
                        if commentsDetailed.authorId == Prefs.userId.description {
                            return 45.0 + heightCalc + 40.0 + 30.0
                        }
                        else{
                            return 45.0 + heightCalc + 40.0
                        }
                    }
                    else{
                        if commentsDetailed.authorId == Prefs.userId.description {
                            return 45.0 + 40.0 + 30.0
                        }
                        else{
                            return 45.0 + 40.0
                        }
                    }
                }
                else {
                     CLSLogv("in the else for defining commentsDetailed %a",getVaList(["commentsdetailed"]))
                    return 80.0
                }
            }
            else {
                CLSLogv("in the condition for checking commentsDetailed = nil - true %a", getVaList(["CRASH RELATED TO RETURNING 80 IF ARRAY IS NIL?"]))
                return 80.0
            }

        }
    }
user2363025
  • 6,365
  • 19
  • 48
  • 89
  • 1
    Was there no Exception Type & are you sure commentsDetailed.comment cannot be nil? – Naoto Ida Dec 15 '15 at 09:31
  • @NaotoIda at the top of the crash report it says: EXC_BREAKPOINT – user2363025 Dec 15 '15 at 09:32
  • @NaotoIda I'm sure commentsDetailed.comment cannot be nil. I did the web services myself – user2363025 Dec 15 '15 at 09:34
  • Did you set the height anywhere else? In the viewDidLoad maybe? Or in the storyboard or in the cell? You could have 2 conflicting heights. Also, do you have any gestures in your app? – Lukesivi Dec 15 '15 at 11:22
  • @lukesIvi I'm not setting a global cell height no, just implementing the heightForRow method. The storyboard does not have a constraint on the height as the cellsize is dynamic. I do have gestures in my header cells. Would that be related? – user2363025 Dec 15 '15 at 11:36
  • 1
    You've posted the stack trace for the thread but not the error log. What did it say in the error log? It will say something like "Unexpectedly found nil when unwrapping optional" or something like that. Readable text. – Fogmeister Dec 15 '15 at 11:51
  • @Fogmeister I can't reproduce the issue and retrieve an error log. if I could, that would be great. I'm just getting a crash report in from crashlytics and I can't see and nice readable errors, I just get the stack trace :( – user2363025 Dec 15 '15 at 11:54
  • It could be related to the gesture recognizer @user2363025. I've seen something similar pop-up with a colleague's project. Can you/did you test some related gestures with that test device? I'm also finding out to see what happened to the friend's project. – Lukesivi Dec 15 '15 at 12:42
  • Checked with the friend. He was having an issue when looping through an array on a gesture recognizer. Assuming that's not relevant to your problem. File a bug with Apple. – Lukesivi Dec 15 '15 at 13:19
  • As others covered it you do a lot of forced unwrapping instead of `if let ...` or `guard let ...`, those are possible causes, and you unwrap `commentsDetailed.comment!` without checking if it's `nil` or not. – Dániel Nagy Dec 15 '15 at 13:47
  • Do they have a jailbroken device? It might have something to do with the font, or it might be an error in Swift's code with naming your variable `commentsDetailed` in `let commentsDetailed = self.commentsDetailed![indexPath.row-3]`. Try naming it something else, like `let commentsDetailedValue = self.commentsDetailed![indexPath.row-3]` – Jojodmo Dec 16 '15 at 00:28
  • @DánielNagy Jojodmo thanks for the feedback, I've sent out a test build to the user with better crash logs and put an if let around commentsDetailed.comment! which understandably people believe is the only place where the crash must be happening. I'll just have to wait and see what the user gets back with – user2363025 Dec 16 '15 at 10:23
  • @Fogmeister I'll update the question with my latest code that checks all vars aren't nil. The user is still experiencing the issue – user2363025 Dec 18 '15 at 09:19
  • @jojodmo No her device is not jailbroken according to twitter fabric. I've updated the code for checking variables as nil – user2363025 Dec 18 '15 at 09:23

3 Answers3

1

I think the only possible point where the second else can fail is the commentsDetailed.comment! unwrapping, which should fail in case it were equal to nil. The rest seems perfectly robust, including the heightForView method. If checking commentsDetailed.comment != nil doesn't do the trick, I'll start thinking it's some random 9.2 early bug...

Bartserk
  • 675
  • 6
  • 18
  • I know commentsDetailed.comment can never be nil because i have that built into the query – user2363025 Dec 15 '15 at 10:08
  • its hardly that I need to use 'return 45.0 + heightCalc + 40.0 + 30.0' instead of 'return 45 + heightCalc + 40 + 30', this is the only thing i can think of but surely if that were an issue it wouldn't happen intermittently and it wouldn't be specific to one user?? – user2363025 Dec 15 '15 at 10:44
  • That's why I suspected it was either data-related or sdk-related. I haven't worked with version 9.2 yet, but if it ends up being an OS bug it definitely won't be the first time... – Bartserk Dec 15 '15 at 14:56
  • thanks for the feedback, I've sent out a test build to the user with better crash logs and put an if let around commentsDetailed.comment! which understandably people believe is the only place where the crash must be happening. I'll just have to wait and see what the user gets back with – user2363025 Dec 16 '15 at 10:24
  • i updated the code and put if lets around everything and put in some extra custom logs with crashlytics and it is still crashing for her. Better yet, now I am not getting crash reports for her device :( – user2363025 Dec 17 '15 at 11:40
1

The error is array out of bounce at the last else closure like you said:

if self.commentsDetailed != nil && self.commentsDetailed!.count >= (indexPath.row - 3)
     {
        let commentsDetailed = self.commentsDetailed![indexPath.row-3]

If for example the array is size 1, then the last element you can index is arr[0] but count >= (indexPath.row - 3) will let indexing arr[1] which will cause the error.

There are also other fixes you can do to optimize since this method is called repeatedly. (I'd suggest maybe having the fonts and other variables outside so that it doesn't create them each time. There maybe such optimization behind but I'm not sure).

I had to re-write the whole thing playground to find the problem so I guess I'll just paste the code here :)

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: 
    NSIndexPath) -> CGFloat {
    var screenWidth = UIScreen.mainScreen().bounds.size.width
    let screenHeight = UIScreen.mainScreen().bounds.size.height

    switch indexPath.row {

    case 0:

        guard let font = UIFont(name: "Helvetica Neue", size: 17.0) else { 
            print("Font not Found !")
            break
        }
        let heightCalc = heightForView(self.postDescription! ?? "", font: font, width: screenWidth - 32)

        guard let photoWidth = self.photoWidth, let photoHeight = self.photoHeight else {
            return 136 + heightCalc + 30
        }
        let imageAspectRatio = photoWidth / photoHeight
        var imageViewFrameHeight = screenWidth / imageAspectRatio
        if self.portBool {
            if imageViewFrameHeight > (screenHeight - 64) {
                screenWidth = screenWidth * 0.60
                imageViewFrameHeight = imageViewFrameHeight * 0.60
            }
        }
        return imageViewFrameHeight + 136 + heightCalc + 26
        //return 557

    case 1: return 50.0
    case 2: return 40.0

    case _ where self.commentsDetailed != nil && indexPath.row >= 3: 

        let index = indexPath.row - 3
        //I think your problem was here (your index can not be equal to the count!)
        guard let detailed = self.commentsDetailed where detailed.count > index
            else { break }

        let commentsDetailed = detailed[index]
        guard let font = UIFont(name: "Helvetica Neue", size: 14.0) else { 
            break //font not found
        }

        let heightCalc = heightForView(commentsDetailed.comment! ?? "", font: font, width: screenWidth - 51)

        if commentsDetailed.authorId == Prefs.userId.description { //make sure author id is always string. sounds like a number
            return 45 + heightCalc + 40 + 30
            //return 131.5
        }
        else{
            return 45 + heightCalc + 40
            //return 101.5
        }

    default: return 80.0
    }
}
Lukas
  • 3,423
  • 2
  • 14
  • 26
  • the reason for checking if indexPath.row - 3 is >= to 0 is because the first 3 cells are not coming from the array – user2363025 Dec 15 '15 at 11:53
  • Ok but thats the only place the code could break: let commentsDetailed = self.commentsDetailed![indexPath.row-3]. I'd put it inside: if self.commentsDetailed!count > (indexPath.row - 3) { } Otherwise, there is a chance you might access self.commentsDetailed![self.commentsDetailed!.count] //which is illegal – Lukas Dec 15 '15 at 12:11
  • thanks for the response but if the issue really was an array out of bounds, this would be consistently happening and not specific to one user or am I missing something? – user2363025 Dec 15 '15 at 12:29
  • I've updated the code as suggested checking for nils and also, changed my check if indexPath.row > 3 rather than >= 3. The user is still getting intermittent crashes – user2363025 Dec 18 '15 at 09:24
0

there is still a little bit of inconsistency in your code. try to distinguish between self.comentsDetailed and comentsDetailed in you code. try to choose another name for the local value let cd = self.commentsDetailed![indexPath.row-3] for an example, and next use this value where it is necessary in next statements. this can help you to see what wrong happens in your code.

user3441734
  • 16,722
  • 2
  • 40
  • 59