5

Is there any up to date way to convert links inside the text? I'm getting this kind of text from an API:

var someText: String = "with banks (for example to the sometimes controversial but leading exchange <a href="https://www.coingecko.com/en/exchanges/bitfinex">Bitfinex</a>)."

How can I convert that link inside to a clickable link with the proper name, in the example above: Bitfinex ?

The text could contain multiple links. SwiftUI now supports markdown, manually I could do it like:

Text("[Privacy Policy](https://example.com)")

but how do I do it for a received text from api with multiple links?

Looking for a Swift 5 & SwiftUI 3 solution.

Arturo
  • 3,254
  • 2
  • 22
  • 61
  • 2
    extract the links from your `someText` and use that in your various `Text(...)`. What have you tried so far? – workingdog support Ukraine Jan 24 '22 at 01:08
  • do you want to extract and list all the links in `someText`, then show them as clickable `Text` views? – workingdog support Ukraine Jan 24 '22 at 04:41
  • Nop, I want to display the text as it is with the links inside but converted (clickaable) . For example instead of showing all that html, just showing linkToX which you can click. I don't want to extract them, I need them in the text since it's the description of some items @workingdog – Arturo Jan 24 '22 at 04:44
  • 1
    @LeoDabus I reopened it, it was an accident – Arturo Jan 29 '22 at 02:01

1 Answers1

6

What you have is an html string. You can interpret your html string using NSAttributedString initializer options NSAttributedString.DocumentType.html and initialize a new AttributedString with it. No need to manipulate and/or manually parse your string:


First add this extension to your project:

extension StringProtocol {
    func htmlToAttributedString() throws -> AttributedString {
        try .init(
            .init(
                data: .init(utf8),
                options: [
                    .documentType: NSAttributedString.DocumentType.html,
                    .characterEncoding: String.Encoding.utf8.rawValue
                ],
                documentAttributes: nil
            )
        )
    }
}

Then extend Text to add a custom initializer:

extension Text {
    init(html: String, alert: String? = nil) {
        do {
            try self.init(html.htmlToAttributedString())
        } catch {
            self.init(alert ?? error.localizedDescription)
        }
    }
}

import SwiftUI

struct ContentView: View {
    
    var html = #"with banks (for example to the sometimes controversial but leading exchange <a href="https://www.coingecko.com/en/exchanges/bitfinex">Bitfinex</a>. For more info <a href="https://www.google.com/">Google</a>).""#

    var body: some View {
        Text(html: html)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • Sorry `@Leo Dabus`, I didn't even look at your answer. I went off and did my own thing (as usual). I've deleted my answer. – workingdog support Ukraine Jan 25 '22 at 06:18
  • Something happens that when I use that code, the whole data from the view is blank... it's weird, as if it crashes the view but doesn't display any error or anything happening – Arturo Jan 25 '22 at 22:25
  • Crashing it is not related to that code as it has no force unwrap. Make sure your html has no async dependencies. From the docs **Discussion The HTML importer should not be called from a background thread (that is, the options dictionary includes documentType with a value of html). It will try to synchronize with the main thread, fail, and time out. Calling it from the main thread works (but can still time out if the HTML contains references to external resources, which should be avoided at all costs).** – Leo Dabus Jan 25 '22 at 22:34
  • **The HTML import mechanism is meant for implementing something like markdown (that is, text styles, colors, and so on), not for general HTML import** Also make sure to handle any errors thrown – Leo Dabus Jan 25 '22 at 22:35
  • @Arturo see the updated code. Check if it throws any alert. Not sure why your code is crashing if the previous code was already supposed to simply show the text "Could not parse html" – Leo Dabus Jan 25 '22 at 22:45
  • @LeoDabus checking – Arturo Jan 25 '22 at 22:46
  • Don't forget to check the html string content – Leo Dabus Jan 25 '22 at 22:49
  • I'm seeing this in the console: `=== AttributeGraph: cycle detected through attribute 974048 ===` the content of the string looks good – Arturo Jan 25 '22 at 23:29
  • 1
    @Arturo https://developer.apple.com/forums/thread/126890 – Leo Dabus Jan 26 '22 at 00:08
  • 1
    And https://stackoverflow.com/questions/62869586/how-do-i-debug-swiftui-attributegraph-cycle-warnings/63018486 – Leo Dabus Jan 26 '22 at 00:10