Swift programming
iOS development
phone number integration
call functionality
mobile app development

Calling a phone number in swift

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Calling a phone number from an iOS app does not mean your app places the call itself. What you actually do is ask the system to open a tel URL, which hands control to the Phone app if the device supports calling.

The Basic tel URL Flow

The usual steps are:

  1. sanitize the phone number
  2. build a tel URL
  3. check whether the device can open it
  4. ask UIApplication to open it

A small example:

swift
1import UIKit
2
3func call(number raw: String) {
4    let allowed = "+0123456789"
5    let sanitized = raw.filter { allowed.contains($0) }
6
7    guard !sanitized.isEmpty else {
8        print("Invalid phone number")
9        return
10    }
11
12    guard let url = URL(string: "tel://\(sanitized)") else {
13        print("Could not create tel URL")
14        return
15    }
16
17    guard UIApplication.shared.canOpenURL(url) else {
18        print("This device cannot place phone calls")
19        return
20    }
21
22    UIApplication.shared.open(url)
23}

This works on real iPhone hardware. The simulator cannot actually place phone calls.

Why Sanitizing the Number Matters

Phone numbers often arrive in display-friendly formats such as:

  • '+1 (555) 123-4567'
  • '555-123-4567'
  • '555 123 4567'

Those are fine for display, but the dialing target should be normalized before creating the URL. A simple sanitization pass removes spaces and punctuation so the tel URL is predictable.

For serious international support, you should ideally store or derive a canonical dialable number rather than trusting ad hoc formatting from user input.

A Reusable Helper Pattern

In larger apps, it is cleaner to keep calling logic in a small helper instead of scattering UIApplication.shared.open across view controllers.

swift
1import UIKit
2
3enum DialError: Error {
4    case invalidNumber
5    case unsupported
6    case badURL
7}
8
9final class Dialer {
10    static func dial(_ raw: String, completion: @escaping (Result<Void, DialError>) -> Void) {
11        let allowed = "+0123456789"
12        let sanitized = raw.filter { allowed.contains($0) }
13
14        guard !sanitized.isEmpty else {
15            completion(.failure(.invalidNumber))
16            return
17        }
18
19        guard let url = URL(string: "tel://\(sanitized)") else {
20            completion(.failure(.badURL))
21            return
22        }
23
24        guard UIApplication.shared.canOpenURL(url) else {
25            completion(.failure(.unsupported))
26            return
27        }
28
29        UIApplication.shared.open(url, options: [:]) { success in
30            success ? completion(.success(())) : completion(.failure(.unsupported))
31        }
32    }
33}

That keeps your UI code simpler and makes testing easier if you later abstract the system dependency further.

Add a Confirmation Step for Better UX

Calling is a high-impact action, so many apps confirm before dialing.

swift
1import UIKit
2
3final class ContactViewController: UIViewController {
4    func confirmCall(number: String) {
5        let alert = UIAlertController(
6            title: "Call Contact",
7            message: "Do you want to call \(number)?",
8            preferredStyle: .alert
9        )
10
11        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
12        alert.addAction(UIAlertAction(title: "Call", style: .default) { _ in
13            call(number: number)
14        })
15
16        present(alert, animated: true)
17    }
18}

This prevents accidental taps from immediately triggering a phone action.

Real-Device and Platform Considerations

Even correct code can appear broken if you test in the wrong environment.

Important constraints:

  • the iOS simulator cannot place calls
  • iPads and some devices may not support telephony directly
  • the URL may be valid while the device still cannot complete a call

That is why canOpenURL matters and why testing on real hardware is important for this feature.

tel Versus Old Alternatives

Older discussions sometimes mention telprompt. In modern practice, it is safer to use tel and handle confirmation in your own UI. That keeps the flow predictable and avoids relying on legacy behavior patterns.

Common Pitfalls

The most common mistake is testing only in the simulator and assuming the code is broken because nothing dials. Phone calling requires real device support.

Another issue is building the URL from an unsanitized display string full of spaces or punctuation. Clean the number first.

Developers also sometimes skip canOpenURL and go straight to open, which makes failure handling less clear on unsupported devices.

Finally, do not surprise users with an immediate call on a single tap unless the app context makes that behavior obviously intentional.

Summary

  • In Swift, calling a number is done by opening a tel URL through UIApplication.
  • Sanitize the number before building the URL.
  • Check canOpenURL to handle unsupported devices cleanly.
  • Prefer an app-level confirmation step for safer UX.
  • Test real dialing behavior on actual hardware, not only in the simulator.

Course illustration
Course illustration

All Rights Reserved.