Create fake contacts in iOS: Easy script

When working with integration to the address book in iOS there are many things to consider and keep in mind. For example, if you are working on a project where you need to create a function where you can export all the iOS contacts to an API. In this case, you might want to test the limits of the API by posting something like 10k contacts.

In this blog post, we will create a small SwiftUI app that can create as many fake contacts as possible in the simulator.

You can jump to the bottom of this post if you just want to code or clone it from Git Hub – download project.

How do I add contacts to iOS simulator?

There are a few ways of doing this, in this small app we will create fake contacts using CNMutableContact. We will create some random strings as names and some random numbers as phone numbers. Then we will use the CNContactStore to add them to the simulator.

If you want the contacts to have more details like company name, then feel free to add them.

Create fake contacts app in SwiftUI

Now it’s time to create this simple application that creates fake contacts.

We will begin with creating the UI and then we will create two helper functions that creates random strings and lastly we will create the logic that creates and saves the fake contacts.

Create the UI

So in this application, we want to have the ability to create any number of fake contacts, so our UI will consist of an input field and a button. We will also add an error text field and a success text field.

import SwiftUI
import Contacts

struct CreateFakeContactsView: View {
    @State var howManyContacts: String = ""
    @State var isError: Bool = false
    @State var isWorking: Bool = false
    @State var isShowingDone: Bool = false
    
    var body: some View {
        ZStack {
            VStack {
                TextField("Number of contacts to create", text: $howManyContacts)
                    .keyboardType(.numberPad)
                    .border(.black)
                    .padding()
                
                if isError {
                    Text("You can only use int.")
                        .tint(.red)
                }
                
                if isShowingDone {
                    Text("You created \(howManyContacts) contacts to the phonebook.")
                }

                Button {
                    isWorking = true
                    isError = false
                    if let passedInteger = NumberFormatter().number(from: howManyContacts) {
                        Task {
                            //TODO: Add call to function that creates the fake contacts.
                        }
                    } else {
                        isError = true
                        isWorking = false
                    }
                }label: {
                    Text("Create contacts")
                }
                .buttonStyle(.borderedProminent)
                .disabled(isWorking)
            }
            .padding()
        }
    }
}

The result:

As you can see it’s a pretty basic UI but yet it’s user friendly — just because it’s an application for us to create fake contacts in, doesn’t mean it has to suck UX-wise.

Create random functions

Now it’s time to create two functions that create some random data for us.

We will create a function that creates a random string and then we will create a function that creates a random number. Both these functions will take an integer parameter, so you can easily decide how long the name and phone numbers should be.

func randomString(_ length: Int) -> String {
        
        let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
        return String((0..<length).map{ _ in letters.randomElement()! })
    }
    
    func randomNumber(_ length: Int) -> String {
        let letters = "0123456789"
        return String((0..<length).map{ _ in letters.randomElement()! })
    }

Create the fake contacts

Now it’s time for us to create the logic that creates the fake contacts and saves them to the simulator.

Before we write any code we need to add permission to access the contacts. This is done by adding NSContactsUsageDescription to the plist or “Custom Application Target Properties”. You will find the properties if you click on TARGETS then Info and then you can add them.

Now it’s time to write the code that creates the fake contacts. It’s pretty straightforward — first import Contacts to the SwitUI view and then create a CNMutableContact and save it to the contact store.

func createContacts(_ howManyToCreate: Int) async {
        for _ in 1...howManyToCreate {
            var contactToCreate: CNMutableContact = CNMutableContact()
            
            contactToCreate.givenName = randomString(5)
            contactToCreate.familyName = randomString(5)
            
            contactToCreate.phoneNumbers.append(CNLabeledValue(label: CNLabelPhoneNumberiPhone, value: CNPhoneNumber(stringValue: randomNumber(8)) ))
            let store = CNContactStore()
            let saveRequest = CNSaveRequest()
            
            saveRequest.add(contactToCreate, toContainerWithIdentifier:nil)
            try! store.execute(saveRequest)
        }
        
        isWorking = false
    }

And then add the following to the button action where it currently says “ //TODO: Add call to function that creates the fake contacts.”:

Task {
    await createContacts(passedInteger.intValue)
}

Now you can launch the application and create as many fake contacts.

Complete code to the fake contact app

If you just want the complete code, then here you go:

import SwiftUI
import Contacts

struct ContentView: View {
    @State var howManyContacts: String = ""
    @State var isError: Bool = false
    @State var isWorking: Bool = false
    @State var isShowingDone: Bool = false
    
    var body: some View {
        ZStack {
            VStack {
                TextField("Number of contacts to create", text: $howManyContacts)
                    .keyboardType(.numberPad)
                    .border(.black)
                    .padding()
                
                if isError {
                    Text("You can only use int.")
                        .tint(.red)
                }
                
                if isShowingDone {
                    Text("You created \(howManyContacts) contacts to the phonebook.")
                }

                Button {
                    isWorking = true
                    isError = false
                    if let passedInteger = NumberFormatter().number(from: howManyContacts) {
                        Task {
                            await createContacts(passedInteger.intValue)
                        }
                    } else {
                        isError = true
                        isWorking = false
                    }
                }label: {
                    Text("Create contacts")
                }
                .buttonStyle(.borderedProminent)
                .disabled(isWorking)
            }
            .padding()
        }
    }
    
    func randomString(_ length: Int) -> String {
        
        let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
        return String((0..<length).map{ _ in letters.randomElement()! })
    }
    
    func randomNumber(_ length: Int) -> String {
        let letters = "0123456789"
        return String((0..<length).map{ _ in letters.randomElement()! })
    }
    
    func createContacts(_ howManyToCreate: Int) async {
        for _ in 1...howManyToCreate {
            var contactToCreate: CNMutableContact = CNMutableContact()
            
            contactToCreate.givenName = randomString(5)
            contactToCreate.familyName = randomString(5)
            
            contactToCreate.phoneNumbers.append(CNLabeledValue(label: CNLabelPhoneNumberiPhone, value: CNPhoneNumber(stringValue: randomNumber(8)) ))
            let store = CNContactStore()
            let saveRequest = CNSaveRequest()
            
            saveRequest.add(contactToCreate, toContainerWithIdentifier:nil)
            try! store.execute(saveRequest)
        }
        
        isWorking = false
    }
}

#Preview {
    ContentView()
}
Scroll to Top