Last year I wrote a post that concerned the use of NSAttributedStrings in Swift. In this post I take that code and rewrite it using a functional approach.
The first thing to do is to define functions that return functions.
Note: The book tackles image filters and I transfer this knowledge to attributed strings.
The first thing to do is to define functions that return functions.
typealias CharacterStyle = String -> NSAttributedString typealias ParagraphStyle = [NSAttributedString] -> NSAttributedStringWith these in place, the functions that will return these functions are written:
func bodyText(size:CGFloat, style:UIFontDescriptorSymbolicTraits?) -> CharacterStyle { var desc = UIFontDescriptor(fontAttributes: [UIFontDescriptorTextStyleAttribute:UIFontTextStyleBody]) if let style = style { desc = desc.fontDescriptorWithSymbolicTraits(style) } let font = UIFont(descriptor: desc, size: size) return { string in return NSMutableAttributedString(string: string, attributes:[NSFontAttributeName:font]) } } func paragraph(indent indent:CGFloat, spacing:CGFloat) -> ParagraphStyle { return { attrStrings in let para = NSMutableAttributedString() for s in attrStrings { para.appendAttributedString(s) } let paraStyle = NSMutableParagraphStyle() paraStyle.firstLineHeadIndent = indent paraStyle.paragraphSpacingBefore = spacing para.addAttribute(NSParagraphStyleAttributeName, value: paraStyle, range: NSRange(location: 0,length: para.string.characters.count)) return para } }I'm not going to discuss at length here the process of what is explained in Functional Programming in Swift (Chapter 3: Wrapping Core Image). Instead, these are examples of how the principles could be applied to refine code that I've written previously.
Note: The book tackles image filters and I transfer this knowledge to attributed strings.
Usage
Now the "boilerplate" code has been hidden away, the implementation can take place very simply and yet be flexible:// styling functions are created let bodyStyle = bodyText(12, style: nil) let bodyStyleItalic = bodyText(12, style: .TraitItalic) // build an array of styled attributed strings let attrStrings = [bodyStyle("Hello Swift! This is a tutorial looking at "), bodyStyleItalic("attributed"), bodyStyle(" strings!")] // create a paragraph from the strings let para = paragraph(indent:10.0, spacing: 12.0)(attrStrings)Once character styles have been applied to an array of strings, a paragraph can be constructed from the resulting array of attributed strings. One of the most appealing things about this approach is that it is possible to see immediately the styles being applied to each part of the paragraph.
Notes
Notice the final line of code though, here a function that takes a function is returnedlet para = paragraph(indent:10.0, spacing: 12.0)and immediately employed by passing the argument (attrStrings). If we'd wanted to separate things out then we could've written:
let para = paragraph(indent:10.0, spacing: 12.0) para(attrStrings)But there is no need to.
Finishing up
Finally some code to load this into a view// Create UITextView let view = UITextView(frame: CGRect(x: 0, y: 20, width: CGRectGetWidth(self.view.frame), height: CGRectGetWidth(self.view.frame)-20)) // Add string to UITextView view.attributedText = para // Add UITextView to main view self.view.addSubview(view)and a gist containing the full code.
Comments
Post a Comment