Using non-breaking space in Swift or how to prevent an automatic line break

If you want a better control in line breaking inside UILabel or UITextView you can use a no-break space (NBSP).

If you want a better control in line breaking inside UILabel or UITextView you can use a no-break space that you may also know as non-breakable space (NBSP). In Swift, this is a special character and it is shown like this:

\u{00a0}

So let's imagine that you have for example a US domestic phone number like (555) 123–4567 and you have to display it inside a UILabel along with a text.

Swift — Without Non-Breaking Space
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var label: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Without non-breaking space - phone number may break across lines
        label.text = "Please call us at (555) 123-4567 for more information"
    }
}
Swift — With Non-Breaking Space
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var label: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

        // With non-breaking space - keeps phone number together
        let phoneNumber = "(555)\u{00a0}123–4567"
        label.text = "Please call us at \(phoneNumber) for more information"
    }
}

Common Use Cases

Non-breaking spaces are particularly useful for:

  • Phone numbers: Keep area codes and numbers together
  • Measurements: Keep numbers with their units (100 kg, 50 mph)
  • Names with titles: Keep titles with names (Dr. Smith, Mr. Johnson)
  • Currency: Keep currency symbols with amounts ($29.99, €15.00)
  • Time formats: Keep time components together (3:30 PM)

The non-breaking space character (\u{00a0}) ensures that text elements that should stay together won't be separated by automatic line breaks, giving you better control over text layout in your iOS applications.

Symbolicate a line from a raw crash log on iOS

When your app crashes, it is never a good thing, but hopefully, you have ways to understand what happens. Learn how to symbolicate crash logs manually.

When your app crashes, it is never a good thing, but hopefully, you have ways to understand what happens. If you upload your app directly through Xcode you can find the crashes directly from the organizer window, symbolicate it and even open the line that crashed inside your project. You can also use some crash reporting tools that will do all the work for you.

But sometimes, especially if you work on an SDK, you may receive a crash log by email or sometimes only just the line where the crash happens.

Raw Crash Log Example

Crash Log
Crashed: com.apple.main-thread
0 libswiftCore.dylib 0x3dcd08 swift_isUniquelyReferenced_nonNull_native + 38
1 YourSDK 0x63974 _hidden#10814_ + 36 (__hidden#11065_:36)
2 YourSDK 0x72394 _hidden#10850_ + 80 (__hidden#11065_:80)
3 YourSDK 0x1834c _hidden#10852_ + 4395545212 (__hidden#593_:4395545212)

Symbolicating the Crash

Here the crash is caused by the SDK, but right now it is impossible to know what line of the code generated the crash. There are 3 lines that are really important for us to decrypt: 1, 2, and 3. To symbolicate these lines we need the .dSYM of our SDK. Hopefully when you archive your project Xcode generates the .dSYM file for you.

We are going to use the following command line atos -arch arm64 -o followed by the path of the DWARF file contained inside the .dSYM archive:

Bash
atos -arch arm64 -o YOURSDK.framework.dSYM/Contents/Resources/DWARF/YOURSDK 0x63974

The output may look like this:

YourClassThatCrash.theMethodThatCrash() (in YOURSDK) (YourClassThatCrash.swift:74)

With this it should be much easier to find the crash, correct it and make your users happy.

What's new for AdTech announced during the WWDC 2022

What Apple presented about AdTech: SKAdNetwork 4.0, Ads with SharePlay, Pasteboard access, Location attribution…

Apple released some videos relevant to the Ad Tech industry at WWDC 2022. At Teads, we take very seriously the fact of being up to date with new technologies. Here's a summary of the key announcements.

New Platform Updates

With iOS 16, there are new features about privacy and security:

Location Attribution

The name of the app using the user location will now appear in conjunction with the location symbol system-wide — if an app uses your location, you will know which app, even outside the app.

Pasteboard Access

To access the shared clipboard or simply paste the content from another app, you now have to ask permission. Apple offers controls that allow the user to paste the content of the clipboard with a tap without requiring a full permission prompt.

Device Name Entitlement

Before iOS 16, an app could access the device name (e.g., "Antoine's iPhone"). Now UIDevice.name will return just the model name (iPhone / iPad). You can still access the user-assigned name using a special entitlement, but sharing it with third parties is not permitted.

App Tracking Transparency

For Apple, privacy is a fundamental human right. Tracking is the fact of linking user or device data collected inside your app with data collected from others (apps, websites, offline data) for targeting ads or advertising measurement. If the user denies ATT, you can still gather information for internal use but cannot share it with third parties.

SKAdNetwork 4.0

SKAdNetwork is Apple's privacy-preserving ad-attribution system. Version 4.0 introduces:

Crowd Anonymity

A method to pass information to the ad network depending on the number of installations. If the app has few installations the attribution data sent will be limited. With more installations, more data will be sent. There are 3 levels: Low, Medium, and High.

New Attribution Values

The source identifier replaces the campaign field and expands from two to four digits. The conversion value is split into a fine-grained value (6-bit, 0-63) and a coarse-grained value (low, medium, high). Which value is sent depends on the crowd anonymity level.

Swift
// Conversion value split
enum CoarseGrainedValue {
    case low
    case medium
    case high
}

// Fine-grained value: 6-bit value (0-63)
let fineGrainedValue: Int = 42

// Only one value is sent based on crowd anonymity level

Web Attribution

It is now possible to use SKAdNetwork for ads on the Web (Safari only) for ads that advertise an App Store page.

Apple's Privacy Pillars

  • Data minimization — use only the data you need
  • On-device processing — do not send sensitive data to your server
  • Transparency and control — explain what data you are using
  • Security protections — make sure the data transiting is protected

Adding Dark Mode to your iOS app to make your app bright

With iOS 13 Apple added a dark mode to its operating system. Learn how to implement it in your app.

With iOS 13 Apple added a dark mode to its operating system. Almost two months after the launch there are only few apps that already implement it. I will try to show you how you can implement it in your app and make your users happiest.

Using Apple Dark Mode Compatible Colors

Apple shipped basic system colors with iOS 13. Instead of UIColor.blue, you can use UIColor.systemBlue that gives you a different blue on light and dark mode without any effort.

Swift
if #available(iOS 13, *) {
    view.backgroundColor = .systemBlue
} else {
    view.backgroundColor = .blue
}

Two other useful colors: UIColor.label (black on light, white on dark) and UIColor.systemBackground (white on light, black on dark).

Creating Custom Colors in Code

With iOS 13, Apple added initWithDynamicProvider for UIColor, which lets you access the current traitCollection and know if the user is using dark mode.

Creating the AppColor Protocol

Swift
protocol AppColor {
    var light: UIColor { get }
    var dark: UIColor { get }
    var fallbackColorBeforeiOS13: UIColor { get }
    func color() -> UIColor
}

extension AppColor {
    func color() -> UIColor {
        if #available(iOS 13, *) {
            return UIColor.init { (trait) -> UIColor in
                return trait.userInterfaceStyle == .dark ? self.dark : self.light
            }
        }
        return self.fallbackColorBeforeiOS13
    }
}

Creating an Enum of AppColors

Swift
enum CustomColors: AppColor {
    case primary, secondary

    var light: UIColor {
        switch self {
        case .primary: return UIColor(red: 0, green: 0.8, blue: 0.69, alpha: 1)
        case .secondary: return UIColor(red: 219/255, green: 230/255, blue: 228/255, alpha: 1.0)
        }
    }

    var dark: UIColor {
        switch self {
        case .primary: return light
        case .secondary: return UIColor(red: 0, green: 205/255, blue: 177/255, alpha: 0.3)
        }
    }

    var fallbackColorBeforeiOS13: UIColor {
       return light
    }
}

LaunchScreen & Images

For the launch screen, create a new color set in your assets catalog and enable dark mode appearance. For images, the process is the same: enable dark mode on the image asset and provide dark appearance variants. Your app will automatically load the correct variant based on the user's appearance setting.

Apple made it really easy for developers to implement dark mode, so we should — if we care about our users.

How to make a simple Countdown Timer with SwiftUI

Step-by-step instructions on how to build a countdown timer using the SwiftUI framework.

Apple launched SwiftUI, a framework that allows us to make app interfaces in a 100% swifty way. Here's how to make a countdown timer.

Pre-Requirements

To start with SwiftUI, download the latest build of Xcode 11 and macOS Catalina 10.15. SwiftUI is only available on iOS 13, macOS 10.15, watchOS 6 and iPadOS 13.

Making the Timer Logic

To refresh our interface every second, we use a timer and declare a date for our countdown:

Swift
import SwiftUI

struct ContentView: View {
    @State var date = Date()
    let referenceDate = Date()

    let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

    var body: some View {
        Text("Hello World")
            .onReceive(timer) { input in
                date = input
            }
    }
}

Note here the @State recreates our interface every time the date is updated.

Adding Countdown Logic

Swift
func countDownString(from referenceDate: Date, until date: Date) -> String {
    let calendar = Calendar(identifier: .gregorian)
    let components = calendar.dateComponents([.day, .hour, .minute, .second],
                                             from: referenceDate,
                                             to: date)

    return String(format: "%02d:%02d:%02d:%02d",
                  components.day ?? 0,
                  components.hour ?? 0,
                  components.minute ?? 0,
                  components.second ?? 0)
}

The Complete Code

Swift
import SwiftUI

struct ContentView: View {
    @State var date = Date()
    let referenceDate = Date()

    let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

    var body: some View {
        VStack {
            Text("Countdown Timer")
                .font(.largeTitle)
                .padding()

            Text(countDownString(from: referenceDate, until: date))
                .font(.system(size: 40, design: .monospaced))
                .padding()
                .onReceive(timer) { input in
                    date = input
                }
                .onAppear(perform: {
                    date = Date()
                })
        }
    }

    func countDownString(from referenceDate: Date, until date: Date) -> String {
        let calendar = Calendar(identifier: .gregorian)
        let components = calendar.dateComponents([.day, .hour, .minute, .second],
                                                 from: referenceDate,
                                                 to: date)

        return String(format: "%02d:%02d:%02d:%02d",
                      components.day ?? 0,
                      components.hour ?? 0,
                      components.minute ?? 0,
                      components.second ?? 0)
    }
}

This creates a simple countdown timer that updates every second using SwiftUI's @State property wrapper and the Timer.publish method.