0

My whole app freezes up when line breaks are added to the string I want to fill up a UITextView with.

This freezes up the app:

let testStringLineBreaks = "foooooo \n \n barrrrrr"
self.biographyTextView.text = testStringLineBreaks

This doesn't freeze up the app:

let testStringNoLineBreaks = "foooooobarrrrrr"
self.biographyTextView.text = testStringNoLineBreaks

Why? And how do I fix it? I need to be able to use linebreaks on my UITextView as well because this is where users fill in their profile description.

enter image description here

The app uses about 60 MB. However when it gets stuck on the line:

self.biographyTextView.text = testStringLineBreaks

It keeps going up with about 2 mb per second. I killed the app at 183 mb.

It only happens on iOS 8 and not on iOS 9.

import UIKit

class GFTextView: UITextView {
    let bottomBorder = CALayer()

    @IBInspectable var haveBottomBar:Bool?

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.textContainer.lineFragmentPadding = 0
    }

    func addBottomBar(){
        bottomBorder.frame = CGRectMake(0.0, self.frame.size.height - 1, self.frame.size.width, 1.0);
        bottomBorder.backgroundColor = UIColor.grayColor().CGColor
        self.layer.addSublayer(bottomBorder)
    }

    override func becomeFirstResponder() -> Bool {
        let shouldBecomeFirstResponder = super.becomeFirstResponder()
        bottomBorder.backgroundColor = shouldBecomeFirstResponder ? Constant.ui_applicationMainColor.CGColor : Constant.ui_applicationMainColor.CGColor
        return shouldBecomeFirstResponder
    }

    override func resignFirstResponder() -> Bool {
        let shouldResignFirstResponder = super.resignFirstResponder()
        bottomBorder.backgroundColor = shouldResignFirstResponder ? UIColor.grayColor().CGColor : Constant.ui_applicationMainColor.CGColor
        return shouldResignFirstResponder
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        if let font = self.font {
            self.font = GFFont.fontForDefaultFontName(font.fontName, size: font.pointSize)
        } else {
            self.font = UIFont.systemFontOfSize(12)
        }
        bottomBorder.backgroundColor = UIColor.grayColor().CGColor
    }
}
Rutger Huijsmans
  • 2,330
  • 2
  • 30
  • 67
  • Please clarify. You talk about memory leaks then you talk about app freezes. Which is it? Use the debugger and see where the app is freezing. – rmaddy Jul 14 '16 at 03:15
  • App freezes on the line where I set the biographyTextView's text property with the string containing line breaks. I see the memory steadily rising in the memory report. Will add an image. – Rutger Huijsmans Jul 14 '16 at 03:18
  • As I said, use the debugger to see what your app is doing during this "freeze". When it "freezes", click the Pause button in the debugger and look at the stack traces. – rmaddy Jul 14 '16 at 03:36
  • I tried using the debugger and hitting the pause button when the app freezes. Looking at the stack traces doesn't really give me an insight into why the app appears to be freezing though. I'm probably not doing that correctly. I was using a custom class that inherited from UITextView. I've switched that back to the standard UITextView. This appears to solve the problem I was having. I've added my custom UITextView code to the initial question. – Rutger Huijsmans Jul 14 '16 at 04:39
  • You should not be setting the font or background color (or any other attributes) in your `layoutSubviews` function. Only update frames as needed, that's all. – rmaddy Jul 14 '16 at 04:44
  • Commenting that out did indeed solve my problem. Can you tell me where I should should be setting a standard font for this class instead? – Rutger Huijsmans Jul 14 '16 at 04:54

2 Answers2

1

I see similar question asked here: Swift - Split string over multiple lines

But I just tried to execute your code using xcode Version 7.3.1 (7D1014) Deployment target 9.3. It works fine for me. May be it was issue before but has been resolved with latest version of swift.

@IBOutlet weak var multiline: UITextView! override func viewDidLoad() { super.viewDidLoad() let testStringLineBreaks = "foooooo \n \n barrrrrr"

    self.multiline.text = testStringLineBreaks
    // Do any additional setup after loading the view.
}
Community
  • 1
  • 1
kamal
  • 56
  • 5
  • 1
    Note the OP's comment where the problem is only with iOS 8. – rmaddy Jul 14 '16 at 04:06
  • You might want to check swift version you are using: xcrun swift -version. Swift 2.2 documentation says: String literals can include the following special characters: The escaped special characters \0 (null character), \\ (backslash), \t (horizontal tab), \n (line feed), \r (carriage return), \" (double quote) and \' (single quote)...... I was able to run the code with ios 8 deployment target 8.4 simulator. – kamal Jul 14 '16 at 04:31
1

Based on the fact that you only get the error from your custom UITextView subclass, the problem is obviously from your implementation.

The most likely cause is your implementation of the layoutSubview function. The only types of things you should do in that overridden function is to adjust frames as needed.

Setting the font is probably causing a recursive call to layoutSubviews or something similar.

Setting the background color should be done in the init function. Setting the font should be done later since it depends on the value of a property that won't be set when init is called. The best place to set the font is in an override of the font property's setter.

rmaddy
  • 314,917
  • 42
  • 532
  • 579