HiveBrain v1.2.0
Get Started
← Back to all entries
patternswiftMinor

Chop off trailing newline for Swift's NSAttributedString

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
swiftnewlinensattributedstringchopfortrailingoff

Problem

I've made this extension but I'm touchy around NSAttributedStrings, keenly aware that Swift refuses to use the traditional notion of integer lengths on Unicode Strings, what with their graphemes that can compose and overlap. Also, it feels odd to convert to String to check for the newline. I'm not worried about \r because \n is the standard conversion when coming from HTML
tags. Also is this too long for something so simple? It feels like I'm missing someething

extension NSAttributedString {
    var trailingNewlineChopped: NSAttributedString {
        get {
            guard self.length > 0 else {
                return self
            }
            let lastCharRange = NSMakeRange(self.length - 1, 1)
            let lastChar = self.attributedSubstringFromRange(lastCharRange).string
            guard lastChar == "\n" else {
                return self
            }
            let mutableCopy = NSMutableAttributedString(attributedString: self)
            mutableCopy.deleteCharactersInRange(lastCharRange)
            return mutableCopy
        }
    }
}

Solution

Your method works correctly, as far as I can see.

For a read-only computed property, you don't need to enclose the
getter method in get { }:

var trailingNewlineChopped: NSAttributedString {
    guard self.length > 0 else {
        return self
    }
    let lastCharRange = NSMakeRange(self.length - 1, 1)
    let lastChar = self.attributedSubstringFromRange(lastCharRange).string
    guard lastChar == "\n" else {
        return self
    }
    let mutableCopy = NSMutableAttributedString(attributedString: self)
    mutableCopy.deleteCharactersInRange(lastCharRange)
    return mutableCopy
}


Checking for a trailing newline character can be done with
the hasSuffix() method on the underlying string.

Instead of creating a mutable copy and removing the last character,
you can extract the first length-1 characters instead.

The method then becomes

var trailingNewlineChopped: NSAttributedString {
    if self.string.hasSuffix("\n") {
        return self.attributedSubstringFromRange(NSMakeRange(0, self.length - 1))
    } else {
        return self
    }
}


You can even omit the implicit self., but that is a matter of personal
preference:

var trailingNewlineChopped: NSAttributedString {
    if string.hasSuffix("\n") {
        return self.attributedSubstringFromRange(NSMakeRange(0, length - 1))
    } else {
        return self
    }
}


NSMakeRange will not be available in Swift 3 anymore, so it could
be a good idea to start replacing that by
NSRange(location:, length:) in your code.

Update: Swift 3 changed how Objective-C methods are imported
into Swift:

extension NSAttributedString {

    var trailingNewlineChopped: NSAttributedString {
        if string.hasSuffix("\n") {
            return self.attributedSubstring(from: NSRange(location: 0, length: length - 1))
        } else {
            return self
        }
    }
}

Code Snippets

var trailingNewlineChopped: NSAttributedString {
    guard self.length > 0 else {
        return self
    }
    let lastCharRange = NSMakeRange(self.length - 1, 1)
    let lastChar = self.attributedSubstringFromRange(lastCharRange).string
    guard lastChar == "\n" else {
        return self
    }
    let mutableCopy = NSMutableAttributedString(attributedString: self)
    mutableCopy.deleteCharactersInRange(lastCharRange)
    return mutableCopy
}
var trailingNewlineChopped: NSAttributedString {
    if self.string.hasSuffix("\n") {
        return self.attributedSubstringFromRange(NSMakeRange(0, self.length - 1))
    } else {
        return self
    }
}
var trailingNewlineChopped: NSAttributedString {
    if string.hasSuffix("\n") {
        return self.attributedSubstringFromRange(NSMakeRange(0, length - 1))
    } else {
        return self
    }
}
extension NSAttributedString {

    var trailingNewlineChopped: NSAttributedString {
        if string.hasSuffix("\n") {
            return self.attributedSubstring(from: NSRange(location: 0, length: length - 1))
        } else {
            return self
        }
    }
}

Context

StackExchange Code Review Q#139461, answer score: 8

Revisions (0)

No revisions yet.