Xcode Simulator is a built-in Apple tool that runs iOS applications on a Mac without a physical device. The simulator compiles code for the host's x86_64 architecture, providing high testing speed. Apple Documentation describes the full debugging cycle using the simulator for iPhone, iPad, Apple Watch and Apple TV.
Key Takeaways
Xcode Simulator is a tool for running and debugging iOS applications directly on a Mac. Unlike the Android emulator, Apple's simulator does not emulate the device's ARM processor. Instead, the code is compiled into the machine code of the host architecture (x86_64 on Intel Mac or arm64 on Apple Silicon).
The simulator uses iOS frameworks directly from the SDK, providing access to UIKit, SwiftUI, Foundation and Core Data. According to Apple (WWDC 2024), over 90% of developers use the simulator during the development stage, connecting physical devices only for final testing.
Each version of Xcode includes a set of simulators for different device models and iOS versions. For example, Xcode 16 includes simulators for iPhone 16 Pro with iOS 18, iPad Pro M4 with iPadOS 18, Apple Watch Series 10 and Apple TV 4K.
The simulator is installed together with Xcode from the Mac App Store. To add additional iOS versions use the menu Settings → Platforms. Select a simulator in the build scheme and press Run. Alternatively, launch the simulator via the menu Xcode → Open Developer Tool → Simulator.
// Checking minimum iOS version for simulator
if #available(iOS 18.0, *) {
print("iOS 18 APIs available")
}Understanding the differences between the simulator and a real device is critically important for quality testing. The main differences lie in processor architecture, hardware capabilities and graphics performance.
| Characteristic | Simulator | Real device |
|---|---|---|
| CPU Architecture | x86_64 / arm64 (Mac) | ARM64 (Apple Silicon) |
| GPU Metal | Simulation via Mac GPU | Native Apple GPU |
| Camera | Unavailable | Full-featured |
| Accelerometer/Gyroscope | Unavailable | Hardware sensors |
| Touch ID / Face ID | Simulation via menu | Hardware biometrics |
| Push notifications | Since Xcode 11.4 (.apns file) | APNs server |
| Bluetooth LE | Not supported | Full stack |
Performance in the simulator is usually higher than on a real device because it uses the Mac's powerful processor. This creates a false impression of speed. Animations, Core Data operations and network requests on a real device may run slower.
Be sure to run the application on a real device before release. Critical scenarios: camera and AVFoundation, Bluetooth and CoreBluetooth, push notifications via APNs, file system operations in App Sandbox, graphics performance in Metal, and battery power consumption.
For conditional compilation of code for the simulator, Apple provides TARGET_OS_SIMULATOR in Objective-C and targetEnvironment(simulator) in Swift. This check allows you to add debug logs, mock objects or disable hardware-dependent code.
import UIKit
class CameraViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
#if targetEnvironment(simulator)
showMockCameraPreview()
print("Simulator: using mock camera")
#else
setupRealCameraSession()
#endif
}
}In Objective-C the #if TARGET_OS_SIMULATOR directive works similarly. Use it to disable code that requires hardware sensors or a camera. At compile time for the simulator, this code does not end up in the binary file.
#if TARGET_OS_SIMULATOR
NSLog(@"Running in simulator — camera unavailable");
self.cameraButton.hidden = YES;
#else
self.cameraButton.hidden = NO;
#endifThe TARGET_OS_SIMULATOR check is used in three cases: replacing the camera with a mock object during UI tests, disabling Core Bluetooth to speed up development, and logging debug information that should not end up in the release build. Avoid using the check to change business logic — this can lead to bugs on a real device.
Xcode Simulator supports the full XCTest test suite: Unit tests (XCTestCase), UI tests (XCUITestCase) and performance tests. Testing on the simulator does not require a signed developer certificate, which simplifies CI/CD setup.
import XCTest
final class LoginTests: XCTestCase {
var app: XCUIApplication!
override func setUp() {
continueAfterFailure = false
app = XCUIApplication()
app.launch()
}
func testLoginButtonExists() {
XCTAssertTrue(app.buttons["loginButton"].exists)
}
func testEmptyEmailValidation() {
app.textFields["emailField"].tap()
app.buttons["loginButton"].tap()
let errorLabel = app.staticTexts["errorMessage"]
XCTAssertTrue(errorLabel.exists)
}
}To run tests from the command line use xcodebuild test with the scheme and simulator specified. The -destination parameter defines the specific simulator on which the tests will be run.
# Running Unit Tests on iPhone 16 Simulator, iOS 18
xcodebuild test \
-scheme "MyApp" \
-destination "platform=iOS Simulator,name=iPhone 16,OS=18.0" \
-testPlan "AllTests"Despite its convenience, Xcode Simulator has a number of limitations that can lead to bugs on a real device. The most critical is the lack of ARM emulation: the code is compiled for the host architecture, and the behavior of some operations may differ.
Core Data and file system work faster on the simulator due to the Mac's SSD. On a real device with NAND memory, read/write speed is lower. Test Core Data performance on a device before release, especially for large data sets.
Checking power consumption on the simulator is impossible — the simulator is powered by the Mac. Background modes, including content loading and fetch operations, behave differently on a real device due to battery limitations and the Background Task Scheduler.
The simulator does not have access to the iPhone's hardware sensors. Face ID and Touch ID can be simulated via the simulator menu: Features → Face ID → Matching Face. Accelerometer, gyroscope and barometer are unavailable — code relying on CMDeviceMotion needs to be tested on a device. For Core Location you can set coordinates via Debug → Simulate Location by selecting a GPX file.
Checking iCloud and StoreKit on the simulator is also limited. StoreKit Test allows you to simulate purchases without a real App Store Connect, but checking the Sandbox environment and production purchases requires a physical device. iCloud Drive and CloudKit synchronization on the simulator works incorrectly — Apple recommends testing these scenarios only on real devices.
On Macs with M-series processors, the simulator works fundamentally differently: the code is compiled into native ARM64, as on a real iPhone, rather than x86_64. This significantly narrows the gap between the simulator and the device. Applications running on the Apple Silicon simulator use the same ARM instructions as on a physical iPhone, making performance tests more representative. The difference in Metal and Core Animation performance between the M-series simulator and a real iPhone is minimal compared to the Intel simulator.
Setting up a simulator for CI requires pre-creating the required device and iOS version. On Continuous Integration servers, simulators are not created automatically — they need to be added via xcrun simctl create before running tests.
# Creating simulator for CI
xcrun simctl create \
"iPhone 16 CI" \
"com.apple.CoreSimulator.SimDeviceType.iPhone-16" \
"com.apple.CoreSimulator.SimRuntime.iOS-18-0"
# Running tests on the created simulator
xcodebuild test \
-workspace MyApp.xcworkspace \
-scheme MyApp \
-destination "id=$(xcrun simctl list devices | grep 'iPhone 16 CI' | awk -F'[][]' '{print }')"For parallel testing on CI, configure several simulators with different iOS versions. Xcode Cloud, GitHub Actions and Bitrise support parallel test execution, reducing run time by 2-3 times. Make sure all required iOS simulators for testing are installed on the CI server.
Frequently Asked Questions
The simulator runs on x86_64 architecture and uses the Mac CPU, while a real device runs on ARM64 Apple Silicon. The simulator does not emulate the camera, sensors, GPU Metal, Bluetooth LE or battery. The code is compiled for the host architecture, so performance tests on the simulator are not representative.
Use #if targetEnvironment(simulator) in Swift or #if TARGET_OS_SIMULATOR in Objective-C. These are conditional compilation directives: the code in the block executes only on the simulator. Useful for mock camera objects and debug logs that are unavailable on a real device.
Yes, starting with Xcode 11.4 the simulator supports simulating push notifications via an .apns file with a JSON structure. Drag the file onto the running simulator or use the xcrun simctl push command. Notifications appear fully just like on a real device.
The simulator does not support camera, microphone, accelerometer, gyroscope, TrueDepth, Touch ID (except simulation), Face ID (except simulation), Bluetooth LE and NFC. Metal performance is simulated on the Mac GPU, which does not reflect real iPhone performance. Power consumption cannot be measured.
Create a simulator via xcrun simctl create, then run xcodebuild test with the -destination parameter specifying platform=iOS Simulator and the device name. For parallel testing, create several simulators with different iOS versions in the CI configuration.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also