Part of the label clickable and bold at the same time - swift

import Foundation
import UIKit
extension NSMutableAttributedString {
#discardableResult
public func setAsLink(textToFind: NSMutableAttributedString, linkURL: String) -> Bool {
let foundRange = self.mutableString.range(of: textToFind)
if foundRange.location != NSNotFound {
self.addAttribute(NSLinkAttributeName, value: linkURL, range: foundRange)
return true
}
return false
}
}
#IBDesignable
class SignUpLabel: UILabel {
override func layoutSubviews() {
super.layoutSubviews()
let normalText = "Don't have an account yet? "
let normalString = NSMutableAttributedString(string: normalText)
let boldText = "Sign up now!"
let attrs = [NSFontAttributeName : UIFont.boldSystemFont(ofSize: 14)]
let attributedString = NSMutableAttributedString(string: boldText, attributes: attrs)
normalString.append(attributedString)
self.attributedText = normalString
normalString.setAsLink(textToFind: attributedString, linkURL: "http://www.someaddress.com")
}
}
let foundRange = self.mutableString.range(of: textToFind) requires String but I have declared it as a NSMutableAttributedString so I would be able to add weight to specific part of the label.
I can't figure it out. Can somebody please help me with the fix? I would really appreciate it.

NSMutableAttributedString has a property called string. To access it, and allow for searching, use yourMutableAttributedString.string as the argument.

Related

How to check if text is underlined

I am struggling to determine if some selected text in a UITextView is underlined. I can quite easily check for bold, italics etc with the following code:
let isItalic = textView.font!.fontDescriptor.symbolicTraits.contains(.traitItalic)
However, I can't figure out how to check for underline?
I have just created a sample project and I think you could do something like the following:
class ViewController: UIViewController {
#IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
let attrText1 = NSMutableAttributedString(string: "TestTest", attributes: [.foregroundColor : UIColor.systemTeal, .underlineStyle: NSUnderlineStyle.single.rawValue])
let attrText2 = NSAttributedString(string: " - not underlined", attributes: [.foregroundColor : UIColor.red])
attrText1.append(attrText2)
textView.attributedText = attrText1
}
func isTextUnderlined(attrText: NSAttributedString?, in range: NSRange) -> Bool {
guard let attrText = attrText else { return false }
var isUnderlined = false
attrText.enumerateAttributes(in: range, options: []) { (dict, range, value) in
if dict.keys.contains(.underlineStyle) {
isUnderlined = true
}
}
return isUnderlined
}
#IBAction func checkButtonDidTap(_ sender: UIButton) {
print(isTextUnderlined(attrText: textView.attributedText, in: textView.selectedRange))
}
}
Create an extension to get the selectedRange as NSRange:
extension UITextInput {
var selectedRange: NSRange? {
guard let range = selectedTextRange else { return nil }
let location = offset(from: beginningOfDocument, to: range.start)
let length = offset(from: range.start, to: range.end)
return NSRange(location: location, length: length)
}
}
I believe underline is not part of the font traits, it must rather be an attribute to the text. You might find the answer to this question useful. I hope it helps you! Enumerate over a Mutable Attributed String (Underline Button)
func checkForUnderline(){
let allWords = self.testView.text.split(separator: " ")
for word in allWords {
let result = self.isLabelFontUnderlined(textView: self.testView,
subString: word as NSString)
if(result == true){
print(word+" is underlined")
}else{
print(word+" is not underlined")
}
}
}
func isLabelFontUnderlined (textView: UITextView, subString:
NSString) -> Bool {
let nsRange = NSString(string: textView.text).range(of: subString as
String, options: String.CompareOptions.caseInsensitive)
if nsRange.location != NSNotFound {
return self.isLabelFontUnderlined(textView: textView,
forRange: nsRange)
}
return false
}
func isLabelFontUnderlined (textView: UITextView, forRange: NSRange) ->
Bool{
let attributedText = testView.attributedText!
var isRangeUnderline = false
attributedText.enumerateAttributes(in: forRange,
options:.longestEffectiveRangeNotRequired) { (dict, range, value) in
if dict.keys.contains(.underlineStyle) {
if (dict[.underlineStyle] as! Int == 1){
isRangeUnderline = true
} else{
isRangeUnderline = false
}
}else{
isRangeUnderline = false
}
}
return isRangeUnderline
}

UITextView Attributed text with 2 links, each with different colors not working

I want to display in an attributed string 2 links, each link with a different color. I do not understand how to do that. It will always set just one color. I've been struggling with this for days and still can't figure out how to make it work. Does anybody know? I can set two colors but not for links! All links are the same color.
This is my whole implementation: (UPDATE)
var checkIn = ""
var friends = ""
//MARK: Change Name Color / Font / Add a second LABEL into the same label
func setColorAndFontAttributesToNameAndCheckIn() {
let nameSurname = "\(postAddSetup.nameSurname.text!)"
checkIn = ""
friends = ""
if selectedFriends.count == 0 {
print("we have no friends...")
friends = ""
} else if selectedFriends.count == 1 {
print("we have only one friend...")
friends = ""
friends = " is with \(self.firstFriendToShow)"
} else if selectedFriends.count > 1 {
print("we have more than one friend...")
friends = ""
friends = " is with \(self.firstFriendToShow) and \(self.numberOfFriendsCount) more"
}
if checkIn == "" {
checkIn = ""
}
var string = postAddSetup.nameSurname.text
string = "\(nameSurname)\(friends)\(checkIn) "
let attributedString = NSMutableAttributedString(string: string!)
attributedString.addAttribute(NSFontAttributeName, value: UIFont.boldSystemFont(ofSize: 14), range: (string! as NSString).range(of: nameSurname))
attributedString.addAttribute(NSFontAttributeName, value: UIFont.systemFont(ofSize: 13), range: (string! as NSString).range(of: checkIn))
attributedString.addAttribute(NSFontAttributeName, value: UIFont.systemFont(ofSize: 13), range: (string! as NSString).range(of: friends))
attributedString.addLink("checkIn", linkColor: UIColor.darkGray, text: checkIn)
attributedString.addLink("tagFriends", linkColor: UIColor.red, text: friends)
//attributedString.addAttribute(NSLinkAttributeName, value: "checkIn", range: (string! as NSString).range(of: checkIn))
//attributedString.addAttribute(NSLinkAttributeName, value: "tagFriends", range: (string! as NSString).range(of: friends))
//postAddSetup.nameSurname.linkTextAttributes = [NSForegroundColorAttributeName:UIColor.redIWorkOut(), NSFontAttributeName: UIFont.systemFont(ofSize: 13)]
//attributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.darkGray, range: (string! as NSString).range(of: checkIn))
postAddSetup.nameSurname.attributedText = attributedString
print("atribute: \(attributedString)")
}
func string1Action() {
print("action for string 1...")
}
func string2Action() {
print("action for string 2...")
}
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
if URL.absoluteString == "string1" {
string1Action()
} else if URL.absoluteString == "string2" {
string2Action()
}
return false
}
extension NSMutableAttributedString {
func addLink(_ link: String, linkColor: UIColor, text: String) {
let pattern = "(\(text))"
let regex = try! NSRegularExpression(pattern: pattern,
options: NSRegularExpression.Options(rawValue: 0))
let matchResults = regex.matches(in: self.string,
options: NSRegularExpression.MatchingOptions(rawValue: 0),
range: NSRange(location: 0, length: self.string.characters.count))
for result in matchResults {
self.addAttribute(NSLinkAttributeName, value: link, range: result.rangeAt(0))
self.addAttribute(NSForegroundColorAttributeName, value: linkColor, range: result.rangeAt(0))
}
}
}
I have used in a project this NSMutableAttributedString extension adapted from this Article.
Using NSRegularExpression you can assign your respective color matching the range of your link text:
The extension:
extension NSMutableAttributedString {
func addLink(_ link: String, linkColor: UIColor, text: String) {
let pattern = "(\(text))"
let regex = try! NSRegularExpression(pattern: pattern,
options: NSRegularExpression.Options(rawValue: 0))
let matchResults = regex.matches(in: self.string,
options: NSRegularExpression.MatchingOptions(rawValue: 0),
range: NSRange(location: 0, length: self.string.characters.count))
for result in matchResults {
self.addAttribute(NSLinkAttributeName, value: link, range: result.rangeAt(0))
self.addAttribute(NSForegroundColorAttributeName, value: linkColor, range: result.rangeAt(0))
}
}
}
Edit:
Set a custom UITextView class to use this extension and using the delegate function shouldInteractWith url it’s possible to simulate the hyperlink logic of UITextView:
class CustomTextView: UITextView {
private let linksAttributes = [NSLinkAttributeName]
override func awakeFromNib() {
super.awakeFromNib()
let tapGest = UITapGestureRecognizer(target: self, action: #selector(self.onTapAction))
self.addGestureRecognizer(tapGest)
}
#objc private func onTapAction(_ tapGest: UITapGestureRecognizer) {
let location = tapGest.location(in: self)
let charIndex = self.layoutManager.characterIndex(for: location, in: self.textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
if charIndex < self.textStorage.length {
var range = NSMakeRange(0, 0)
for linkAttribute in linksAttributes {
if let link = self.attributedText.attribute(linkAttribute, at: charIndex, effectiveRange: &range) as? String {
guard let url = URL(string: link) else { return }
_ = self.delegate?.textView?(self, shouldInteractWith: url, in: range, interaction: .invokeDefaultAction)
}
}
}
}
}
How to use:
attributedString.addLink(yourLinkUrl, linkColor: yourLinkColor, text: yourLinkText)
let textView = CustomTextView()
textView.attributedText = attributedString

Swift 3 - how do I add clickable links to another view controller in the body of a TextView? [duplicate]

I am trying to display an attributed string in a UITextview with clickable links. I've created a simple test project to see where I'm going wrong and still can't figure it out. I've tried enabling user interaction and setting the shouldInteractWithURLs delegate method, but it's still not working. Here's my code (for a view controller that only contains a textview)
#IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let string = "Google"
let linkString = NSMutableAttributedString(string: string)
linkString.addAttribute(NSLinkAttributeName, value: NSURL(string: "https://www.google.com")!, range: NSMakeRange(0, string.characters.count))
linkString.addAttribute(NSFontAttributeName, value: UIFont(name: "HelveticaNeue", size: 25.0)!, range: NSMakeRange(0, string.characters.count))
textView.attributedText = linkString
textView.delegate = self
textView.selectable = true
textView.userInteractionEnabled = true
}
And here are the delegate methods I've implemented:
func textViewShouldBeginEditing(textView: UITextView) -> Bool {
return false
}
func textView(textView: UITextView, shouldInteractWithURL URL: NSURL, inRange characterRange: NSRange) -> Bool {
return true
}
This still isn't working. I've searched on this topic and nothing has helped yet. Thanks so much in advance.
Just select the UITextView in your storyboard and go to "Show Attributes inspector" and select selectable and links. As the image below shows. Make sure Editable is unchecked.
For swift3.0
override func viewDidLoad() {
super.viewDidLoad()
let linkAttributes = [
NSLinkAttributeName: NSURL(string: "http://stalwartitsolution.co.in/luminutri_flow/terms-condition")!
] as [String : Any]
let attributedString = NSMutableAttributedString(string: "Please tick box to confirm you agree to our Terms & Conditions, Privacy Policy, Disclaimer. ")
attributedString.setAttributes(linkAttributes, range: NSMakeRange(44, 18))
attributedString.addAttribute(NSUnderlineStyleAttributeName, value: NSNumber(value: 1), range: NSMakeRange(44, 18))
textview.delegate = self
textview.attributedText = attributedString
textview.linkTextAttributes = [NSForegroundColorAttributeName: UIColor.red]
textview.textColor = UIColor.white
}
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
return true
}
Swift 3 iOS 10: Here's Clickable extended UITextView that detect websites inside the textview automatically as long as the link start with www. for example: www.exmaple.com if it exist anywhere in the text will be clickable. Here's the class:
import Foundation
import UIKit
public class ClickableTextView:UITextView{
var tap:UITapGestureRecognizer!
override public init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
print("init")
setup()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
func setup(){
// Add tap gesture recognizer to Text View
tap = UITapGestureRecognizer(target: self, action: #selector(self.myMethodToHandleTap(sender:)))
// tap.delegate = self
self.addGestureRecognizer(tap)
}
func myMethodToHandleTap(sender: UITapGestureRecognizer){
let myTextView = sender.view as! UITextView
let layoutManager = myTextView.layoutManager
// location of tap in myTextView coordinates and taking the inset into account
var location = sender.location(in: myTextView)
location.x -= myTextView.textContainerInset.left;
location.y -= myTextView.textContainerInset.top;
// character index at tap location
let characterIndex = layoutManager.characterIndex(for: location, in: myTextView.textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
// if index is valid then do something.
if characterIndex < myTextView.textStorage.length {
let orgString = myTextView.attributedText.string
//Find the WWW
var didFind = false
var count:Int = characterIndex
while(count > 2 && didFind == false){
let myRange = NSRange(location: count-1, length: 2)
let substring = (orgString as NSString).substring(with: myRange)
// print(substring,count)
if substring == " w" || (substring == "w." && count == 3){
didFind = true
// print("Did find",count)
var count2 = count
while(count2 < orgString.characters.count){
let myRange = NSRange(location: count2 - 1, length: 2)
let substring = (orgString as NSString).substring(with: myRange)
// print("Did 2",count2,substring)
count2 += 1
//If it was at the end of textView
if count2 == orgString.characters.count {
let length = orgString.characters.count - count
let myRange = NSRange(location: count, length: length)
let substring = (orgString as NSString).substring(with: myRange)
openLink(link: substring)
print("It's a Link",substring)
return
}
//If it's in the middle
if substring.hasSuffix(" "){
let length = count2 - count
let myRange = NSRange(location: count, length: length)
let substring = (orgString as NSString).substring(with: myRange)
openLink(link: substring)
print("It's a Link",substring)
return
}
}
return
}
if substring.hasPrefix(" "){
print("Not a link")
return
}
count -= 1
}
}
}
func openLink(link:String){
if let checkURL = URL(string: "http://\(link.replacingOccurrences(of: " ", with: ""))") {
if UIApplication.shared.canOpenURL(checkURL) {
UIApplication.shared.open(checkURL, options: [:], completionHandler: nil)
print("url successfully opened")
}
} else {
print("invalid url")
}
}
public override func didMoveToWindow() {
if self.window == nil{
self.removeGestureRecognizer(tap)
print("ClickableTextView View removed from")
}
}
}

How to use a NSNumberFormatter with an AttributedString?

I have been unable to find anything that works on the subject of using an attributed text in a NSTextField with a NumberFormatter. What I want to accomplish is very simple. I would like to use a NumberFormatter on an editable NSTextField with attributed text and keep the text attributed.
Currently, I have subclassed NSTextFieldCell and implemented it as so:
class AdjustTextFieldCell: NSTextFieldCell {
required init(coder: NSCoder) {
super.init(coder: coder)
let attributes = makeAttributes()
allowsEditingTextAttributes = true
attributedStringValue = AttributedString(string: stringValue, attributes: attributes)
//formatter = TwoDigitFormatter()
}
func makeAttributes() -> [String: AnyObject] {
let style = NSMutableParagraphStyle()
style.minimumLineHeight = 100
style.maximumLineHeight = 100
style.paragraphSpacingBefore = 0
style.paragraphSpacing = 0
style.alignment = .center
style.lineHeightMultiple = 1.0
style.lineBreakMode = .byTruncatingTail
let droidSansMono = NSFont(name: "DroidSansMono", size: 70)!
return [NSParagraphStyleAttributeName: style, NSFontAttributeName: droidSansMono, NSBaselineOffsetAttributeName: -60]
}
}
This implementation adjusts the text in the NSTextField instance to have the shown attributes. When I uncomment the line that sets the formatter property the NSTextField loses its attributes. My NumberFormatter is as follows:
class TwoDigitFormatter: NumberFormatter {
override init() {
super.init()
let customAttribs = makeAttributes()
textAttributesForNegativeValues = customAttribs.attribs
textAttributesForPositiveValues = customAttribs.attribs
textAttributesForZero = customAttribs.attribs
textAttributesForNil = customAttribs.attribs
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
let maxLength = 2
let wrongCharacterSet = CharacterSet(charactersIn: "0123456789").inverted
override func isPartialStringValid(_ partialString: String, newEditingString newString: AutoreleasingUnsafeMutablePointer<NSString?>?, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool {
if partialString.characters.count > maxLength {
return false
}
if partialString.rangeOfCharacter(from: wrongCharacterSet) != nil {
return false
}
return true
}
override func attributedString(for obj: AnyObject, withDefaultAttributes attrs: [String : AnyObject]? = [:]) -> AttributedString? {
let stringVal = string(for: obj)
guard let string = stringVal else { return nil }
let customAttribs = makeAttributes()
var attributes = attrs
attributes?[NSFontAttributeName] = customAttribs.font
attributes?[NSParagraphStyleAttributeName] = customAttribs.style
attributes?[NSBaselineOffsetAttributeName] = customAttribs.baselineOffset
return AttributedString(string: string, attributes: attributes)
}
func makeAttributes() -> (font: NSFont, style: NSMutableParagraphStyle, baselineOffset: CGFloat, attribs: [String: AnyObject]) {
let style = NSMutableParagraphStyle()
style.minimumLineHeight = 100
style.maximumLineHeight = 100
style.paragraphSpacingBefore = 0
style.paragraphSpacing = 0
style.alignment = .center
style.lineHeightMultiple = 1.0
style.lineBreakMode = .byTruncatingTail
let droidSansMono = NSFont(name: "DroidSansMono", size: 70)!
return (droidSansMono, style, -60, [NSParagraphStyleAttributeName: style, NSFontAttributeName: droidSansMono, NSBaselineOffsetAttributeName: -60])
}
}
As you can see from the code directly above I have tried:
Setting the textAttributesFor... properties.
Overriding attributedString(for obj: AnyObject, withDefaultAttributes attrs: [String : AnyObject]? = [:])
I have tried both these solution separately from each other and together, of which none of the attempts worked.
TLDR: Is it possible to use attributed text and a NumberFormatter at the same time? If so, how? If not, how can I limit a NSTextField with attributed text to digits only and two characters without using a NumberFormatter?
For anyone in the future who wants to achieve the behavior I was able to do it by subclassing NSTextView and essentially faking a NSTextField like so:
class FakeTextField: NSTextView {
required init?(coder: NSCoder) {
super.init(coder: coder)
delegate = self
let droidSansMono = NSFont(name: "DroidSansMono", size: 70)!
configure(lineHeight: frame.size.height, alignment: .center, font: droidSansMono)
}
func configure(lineHeight: CGFloat, alignment: NSTextAlignment, font: NSFont) {
//Other Configuration
//Define and set typing attributes
let style = NSMutableParagraphStyle()
style.minimumLineHeight = lineHeight
style.maximumLineHeight = lineHeight
style.alignment = alignment
style.lineHeightMultiple = 1.0
typingAttributes = [NSParagraphStyleAttributeName: style, NSFontAttributeName: font]
}
}
extension TextField: NSTextViewDelegate {
func textView(_ textView: NSTextView, shouldChangeTextIn affectedCharRange: NSRange, replacementString: String?) -> Bool {
if let oldText = textView.string, let replacement = replacementString {
let newText = (oldText as NSString).replacingCharacters(in: affectedCharRange, with: replacement)
let numberOfChars = newText.characters.count
let wrongCharacterSet = CharacterSet(charactersIn: "0123456789").inverted
let containsWrongCharacters = newText.rangeOfCharacter(from: wrongCharacterSet) != nil
return numberOfChars <= 2 && !containsWrongCharacters
}
return false
}
}
With this class, all you need to do is set the NSTextView in your storyboard to this class and change the attributes and shouldChangeTextIn to suit your needs. In this implementation, the "TextField" has various attributes set and is limited to two characters and only digits.
You subclass NSNumberFormatter with the following:
final class ChargiePercentageNumberFormatter: NumberFormatter {
override func attributedString(for obj: Any, withDefaultAttributes attrs: [NSAttributedString.Key : Any]? = nil) -> NSAttributedString? {
guard let obj = obj as? NSNumber else {
return nil;
}
guard let numberString = self.string(from: obj) else {
return nil
}
let font = NSFont(name: "Poppins-Regular", size: 16)!
let attrs: [NSAttributedString.Key: Any] = [.font: font, .kern: 1.2]
let result = NSAttributedString(string: numberString, attributes: attrs)
return result
}
}

UITextView change text color of specific text

I want to change the text color of a specific text within a UITextView which matches an index of an array. I was able to slightly modify this answer but unfortunatly the text color of each matching phrase is only changed once.
var chordsArray = ["Cmaj", "Bbmaj7"]
func getColoredText(textView: UITextView) -> NSMutableAttributedString {
let text = textView.text
let string:NSMutableAttributedString = NSMutableAttributedString(string: text)
let words:[String] = text.componentsSeparatedByString(" ")
for word in words {
if (chordsArray.contains(word)) {
let range:NSRange = (string.string as NSString).rangeOfString(word)
string.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: range)
}
}
chords.attributedText = string
return string
}
Outcome
In case, someone needs it in swift 4. This is what I get from my Xcode 9 playground :).
import UIKit
import PlaygroundSupport
class MyViewController : UIViewController
{
override func loadView()
{
let view = UIView()
view.backgroundColor = .white
let textView = UITextView()
textView.frame = CGRect(x: 150, y: 200, width: 200, height: 20)
textView.text = "#Kam #Jam #Tam #Ham"
textView.textColor = .black
view.addSubview(textView)
self.view = view
let query = "#"
if let str = textView.text {
let text = NSMutableAttributedString(string: str)
var searchRange = str.startIndex..<str.endIndex
while let range = str.range(of: query, options: NSString.CompareOptions.caseInsensitive, range: searchRange) {
text.addAttribute(NSAttributedStringKey.foregroundColor, value: UIColor.gray, range: NSRange(range, in: str))
searchRange = range.upperBound..<searchRange.upperBound
}
textView.attributedText = text
}
}
}
PlaygroundPage.current.liveView = MyViewController()
I think for swift 3, you need to convert Range(String.Index) to NSRange manually like this.
let start = str.distance(from: str.startIndex, to: range.lowerBound)
let len = str.distance(from: range.lowerBound, to: range.upperBound)
let nsrange = NSMakeRange(start, len)
text.addAttribute(NSAttributedStringKey.foregroundColor, value: UIColor.gray, range: nsrange)
Swift 4.2 and 5
let string = "* Your receipt photo was not clear or did not capture the entire receipt details. See our tips here.\n* Your receipt is not from an eligible grocery, convenience or club store."
let attributedString = NSMutableAttributedString.init(string: string)
let range = (string as NSString).range(of: "See our tips")
attributedString.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.blue, range: range)
txtView.attributedText = attributedString
txtView.isUserInteractionEnabled = true
txtView.isEditable = false
Output
Sorry, I just noticed your message. Here is a working example (tested in a playground):
import UIKit
func apply (string: NSMutableAttributedString, word: String) -> NSMutableAttributedString {
let range = (string.string as NSString).rangeOfString(word)
return apply(string, word: word, range: range, last: range)
}
func apply (string: NSMutableAttributedString, word: String, range: NSRange, last: NSRange) -> NSMutableAttributedString {
if range.location != NSNotFound {
string.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: range)
let start = last.location + last.length
let end = string.string.characters.count - start
let stringRange = NSRange(location: start, length: end)
let newRange = (string.string as NSString).rangeOfString(word, options: [], range: stringRange)
apply(string, word: word, range: newRange, last: range)
}
return string
}
var chordsArray = ["Cmaj", "Bbmaj7"]
var text = "Cmaj Bbmaj7 I Love Swift Cmaj Bbmaj7 Swift"
var newText = NSMutableAttributedString(string: text)
for word in chordsArray {
newText = apply(newText, word: word)
}
newText