Duncan C Duncan C - 3 months ago 340x
iOS Question

How to make a clickable link in an NSAttributedString for a

It's trivial to make hyperlinks clickable in a

. You just set the "detect links" checkbox on the view in IB, and it detects http links and turns them into hyperlinks.

However, that still means that what the user sees is the "raw" link. RTF files and HTML both allow you to set up a user-readable string with a link "behind" it.

It's easy to install attributed text into a text view (or a
, for that matter.) However, if that attributed text includes a link, the link is not clickable.

Is there a way to make user-readable text clickable in a
, or

The markup is different on SO, but here is the general idea. What I want is text like this:

This morph was generated with Face Dancer, Click to view in the app store.

The only thing I can get is this:

This morph was generated with Face Dancer, Click on http://tinyurl.com/facedancer to view in the app store.


The heart of my question was that I wanted to be able to create clickable links in text views/fields/labels without having to write custom code to manipulate the text and add the links. I wanted it to be data-driven.

I finally figured out how to do it. The issue is that IB doesn't honor embedded links.

Furthermore, the iOS version of NSAttributedString doesn't let you initialize an attributed string from an RTF file. The OS X version of NSAttributedString does have an initializer that takes an RTF file as input.

NSAttributedString conforms to the NSCoding protocol, so you can convert it to/from NSData

I created an OS X command line tool that takes an RTF file as input and outputs a file with the extension .data that contains the NSData from NSCoding. I then put the .data file into my project and add a couple of lines of code that loads the text into the view. The code looks like this (this project was in Swift) :

If we can load a file called "Dates.data" from the bundle and convert it to an attributed string,
install it in the dates field. The contents contain clickable links with custom URLS to select
each date.
  let datesPath = NSBundle.mainBundle().pathForResource("Dates", ofType: "data"),
  let datesString = NSKeyedUnarchiver.unarchiveObjectWithFile(datesPath) as? NSAttributedString
  datesField.attributedText = datesString

For apps that use a lot of formatted text, I create a build rule that tells Xcode that all the .rtf files in a given folder are source and the .data files are the output. Once I do that, I simply add .rtf files to the designated directory, (or edit existing files) and the build process figures out that they are new/updated, runs the command line tool, and copies the files into the app bundle. It works beautifully.

I wrote a blog post that links to a sample (Swift) project demonstrating the technique. You can see it here:

Creating clickable URLs in a UITextField that open in your app