0

I am using an extension to parse HTML text into an attributed string from a dynamically retrieved post.

I notice now that my app is crashing when retrieving a post that has empty content.

extension NSAttributedString {

    public convenience init?(HTMLString html: String, font: UIFont? = nil) throws {

        let options: [String: Any] = [...]

        guard let data = html.data(using: .utf8, allowLossyConversion: true) else {
            throw NSError(domain: "Parse Error", code: 0, userInfo: nil)
        }

        if let font = font {
            guard let attr = try? NSMutableAttributedString(data: data, options: options, documentAttributes: nil) else {
                throw NSError(domain: "Parse Error", code: 0, userInfo: nil)
            }
            var attrs = attr.attributes(at: 0, effectiveRange: nil) //APP CRASHES HERE
            attrs[NSFontAttributeName] = font
            attr.setAttributes(attrs, range: NSRange(location: 0, length: attr.length))
            self.init(attributedString: attr)
        } else {
            try? self.init(data: data, options: options, documentAttributes: nil)
        }}}

Here is my exception:

'NSRangeException', reason: 'NSMutableRLEArray objectAtIndex:effectiveRange:: Out of bounds'

I am not very good at handling errors yet, is there a way to prevent this exception from arising regardless of the content?

I tried a do/catch block but it says that no calls to throwing functions happen in this line:

do {
var attrs = attr.attributes(at: 0, effectiveRange: nil) //APP CRASHES HERE
            attrs[NSFontAttributeName] = font
            attr.setAttributes(attrs, range: NSRange(location: 0, length: attr.length))
            self.init(attributedString: attr)
   } catch {
print("error")
}

2 Answers 2

2

Just include the check for empty string in the first guard:

guard !html.isEmpty, let data = html.data(using: .utf8, allowLossyConversion: true) else {...

Or if you want to get an empty attributed string if the string is empty put the check in the font line:

if !html.isEmpty, let font = font { ...
Sign up to request clarification or add additional context in comments.

2 Comments

@Sneak effectiveRange is an inout parameter which has no effect when passing nil.
Great, I am a Swifty newb so the code got me confused thought it was something he set manually, I saw now its the actual parameter. I will upvote your answer
1

Do a simple check on your yourString.characters.count before running the code otherwise NSRange will crash if it's nil.

2 Comments

Are there other types of crashes that I should try to prevent with NSRange?
@JacoboKoenig As long as your NSRange does not go outside the length/count of the Text that you are checking against, you should be ok. If you are unsure of this you can make sure that the string.count does not exceed your effectiveRange and you are good to go!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.