Please note, this blog entry is from a previous course. You might want to check out the current one.
Enhance Smashtag from lecture to highlight (in a different color for each) hashtags, urls and user screen names mentioned in the text of a Tweet (these are known as “mentions”). Note that mentions are already located for you in each Tweet by Twitter and show up as [IndexedKeyword]s in the Tweet class in the supplied Twitter code.
The tweet class provides nearly everything needed – arrays of indexed keywords. What’s left is to choose a color for the keyword type – as public properties of the cell view:
var hashtagColor = UIColor.blueColor() var urlColor = UIColor.redColor() var userMentionsColor = UIColor.greenColor()
An extension of the mutable string class takes an array of indexed key words and a color, loops over the array and adds the foreground color to the range containing the key word:
private extension NSMutableAttributedString { func changeKeywordsColor(keywords: [Tweet.IndexedKeyword], color: UIColor) { for keyword in keywords { addAttribute(NSForegroundColorAttributeName, value: color, range: keyword.nsrange) } } }
Add the media icons to the text – if there are any. Create an mutable attributed string and use the extension to set the color for the keywords. Finally, use the string form the text view:
func updateUI() { ... var text = tweet.text for _ in tweet.media { text += " x" // the icon was not printable here } var attributedText = NSMutableAttributedString(string: text) attributedText.changeKeywordsColor(tweet.hashtags, color: hashtagColor) attributedText.changeKeywordsColor(tweet.urls, color: urlColor) attributedText.changeKeywordsColor(tweet.userMentions, color: userMentionsColor) tweetTextLabel?.attributedText = attributedText ... }
One tiny blemish is that the media URLs are not part of the URLs array and the media array does not contain indexed keywords, therefore they are not colored …
A quick and dirty hack – it is not really proper coding to change third-party code directly – is to adjust the tweet class.
Add a public property to hold the indexed media URLs and fill them in the initializer:
public let mediaMentions = [IndexedKeyword]() init?(data: NSDictionary?) { ... if let mediaEntities = data?.valueForKeyPath(TwitterKey.Media) as? NSArray { ... mediaMentions = getIndexedKeywords(mediaEntities, inText: text, prefix: "h") } ... }
Now it is possible to colorize also the media URLs:
func updateUI() { ... attributedText.changeKeywordsColor(tweet.mediaMentions, color: urlColor) ... }
The complete code for task #1 is available on GitHub.
You are over-complicating it. It’s just a matter of changing attributes in the TwitterTableViewCell updateUI() function:
replace
tweetTextLabel?.text = tweet.text
by :
var attributedText = NSMutableAttributedString(string: tweet.text)
for hashtag in tweet.hashtags {
attributedText.addAttribute(NSForegroundColorAttributeName, value: UIColor.brownColor(), range: hashtag.nsrange)
}
for url in tweet.urls {
attributedText.addAttribute(NSForegroundColorAttributeName, value: UIColor.blueColor(), range: url.nsrange)
}
for userMention in tweet.userMentions {
attributedText.addAttribute(NSForegroundColorAttributeName, value: UIColor.greenColor(), range: userMention.nsrange)
}
tweetTextLabel?.attributedText = attributedText
Writing three times the same code, with different variables, that’s a candidate for using a common method …
… and providing the means to change colors in a public API is also not too bad, is it?
You might also want to take a look at hint #8 😉
… and your code has an unintended side effect. In the code from the lecture, media icons are added to the text label after the text label has been set. If you replace only the code above, you will notice that tweets with media links will not be colorized, as adding the icon to the text, will remove the attributes …
I agree, it can be simplified and colors can be made public. That was just an example to show you that you should not touch the Tweet class and everything you have to do lies in the TweetTableViewCell …
I only touched the Tweet class to make it work on international phones, and to be able to colorize media links …
I really liked the use of extensions in this problem. I confess I avoided at first but realised this was the simplest way. Well done Martin!
OK, my code won’t appear, I give up.
WordPress does not like the camera icon (I had the same problem in the post itself) 😉
More of a question than a comment. Did you start with the downloadable version of Smashtag, or start from scratch? The instructions seem to indicate that was the intent (“Enhance Smashtag from lecture to highlight”).
I based the assignment on the code from the lecture, which I entered while listening to the lecture …
Thanks for the reply, I think I will do the same, rather than start with the project file that is provided.
Hi Martin,
Could you explain why optional chaining is used (with ?) if all @IBOutlets in TweetTableViewCell class are implicitly unwrapped?
For example:
tweetTextLabel?.attributedText = attributedText
Have a look at IBOutlet declarations in Swift by Chris Dzombak
Thanks!
Hi Martin
I now turn to Smashtag and the stanford twitter is not working.
Could you please tell how to change it to log to regulate twitter and how to log in to own twitter account.
I don’t know what to do.
Please help
step by step, use the debugger to where the problem is – the request? does twitter return anything? does to code stumble over the response?
Hi Martin
Thank you for your answer, I found it!!
By the way could you solve snapshot problem for me?
The code is in Project #3 Assignment #3 Extra Task #2 page…
I cannot find the answer for that
Sorry, but I promise to be more cooperative when the new season is in session (should be in a couple weeks?) …