Xcode is Apple's integrated development environment (IDE) for macOS, used to develop software for macOS, iOS, iPadOS, watchOS, and tvOS.
# Install from Mac App Store or Apple Developer Portal
# Requires macOS 12.0 or later for Xcode 14+
# Command line tools
xcode-select --install
# Check version
xcode-select --version
# Switch between Xcode versions
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
# Reset Xcode
sudo xcode-select --reset
Cmd+0 - Show/hide navigator
Cmd+Alt+0 - Show/hide inspector
Cmd+Shift+0 - Show/hide debug area
Cmd+1 to Cmd+9 - Navigate panels
Cmd+Shift+J - Reveal in navigator
Cmd+Shift+O - Open quickly
Cmd+Ctrl+J - Jump to definition
Cmd+Ctrl+Up/Down - Switch between header/implementation
Cmd+L - Go to line
Cmd+/ - Comment/uncomment
Cmd+[ - Shift left
Cmd+] - Shift right
Ctrl+I - Re-indent
Cmd+Alt+[ - Move line up
Cmd+Alt+] - Move line down
Cmd+D - Duplicate line
Ctrl+K - Delete to end of line
Esc - Code completion
Cmd+B - Build
Cmd+R - Run
Cmd+U - Test
Cmd+I - Profile (Instruments)
Cmd+. - Stop
Cmd+Shift+K - Clean build folder
Cmd+K - Clean build folder
F6 - Step over
F7 - Step into
F8 - Step out
Cmd+Y - Activate/deactivate breakpoints
Cmd+\ - Toggle breakpoint
Cmd+Shift+Y - Show/hide debug area
MyApp.xcodeproj/
├── project.pbxproj # Project file
└── project.xcworkspace/ # Workspace (if using CocoaPods)
MyApp/
├── AppDelegate.swift
├── SceneDelegate.swift
├── ViewController.swift
├── Main.storyboard
├── Assets.xcassets/
├── LaunchScreen.storyboard
├── Info.plist
└── Supporting Files/
MyApp/
├── App Lifecycle/
│ ├── AppDelegate.swift
│ └── SceneDelegate.swift
├── Models/
│ ├── User.swift
│ └── Product.swift
├── Views/
│ ├── Custom Views/
│ └── Storyboards/
├── Controllers/
│ ├── HomeViewController.swift
│ └── DetailViewController.swift
├── Services/
│ ├── NetworkService.swift
│ └── DataService.swift
├── Utilities/
│ ├── Extensions/
│ └── Helpers/
└── Resources/
├── Assets.xcassets
└── Fonts/
// IBOutlet connections
class ViewController: UIViewController {
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var textField: UITextField!
@IBOutlet weak var button: UIButton!
// IBAction connections
@IBAction func buttonTapped(_ sender: UIButton) {
print("Button tapped!")
titleLabel.text = textField.text
}
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
}
private func setupUI() {
titleLabel.font = UIFont.systemFont(ofSize: 24, weight: .bold)
button.layer.cornerRadius = 8
button.backgroundColor = .systemBlue
}
}
// Programmatic Auto Layout
override func viewDidLoad() {
super.viewDidLoad()
let stackView = UIStackView()
stackView.axis = .vertical
stackView.spacing = 16
stackView.alignment = .fill
stackView.distribution = .fillEqually
stackView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stackView)
// Anchor-based constraints
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
stackView.heightAnchor.constraint(equalToConstant: 200)
])
// Visual Format Language
let views = ["stackView": stackView]
let horizontalConstraints = NSLayoutConstraint.constraints(
withVisualFormat: "H:|-20-[stackView]-20-|",
options: [],
metrics: nil,
views: views
)
NSLayoutConstraint.activate(horizontalConstraints)
}
// Adaptive layout
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
if traitCollection.horizontalSizeClass == .compact {
// Portrait layout
stackView.axis = .vertical
} else {
// Landscape layout
stackView.axis = .horizontal
}
}
// Size class specific constraints
if traitCollection.horizontalSizeClass == .regular {
// iPad or landscape iPhone
constraintForRegularWidth.isActive = true
constraintForCompactWidth.isActive = false
} else {
// Portrait iPhone
constraintForRegularWidth.isActive = false
constraintForCompactWidth.isActive = true
}
class DebuggingExample {
func processData() {
let data = [1, 2, 3, 4, 5]
for (index, item) in data.enumerated() {
// Set breakpoint here
let result = item * 2
print("Index: \(index), Item: \(item), Result: \(result)")
}
}
func conditionalDebugging() {
for i in 1...100 {
// Conditional breakpoint: i == 50
let result = complexCalculation(i)
print("Result for \(i): \(result)")
}
}
private func complexCalculation(_ input: Int) -> Int {
return input * input + input
}
}
// LLDB Commands
// po variable - Print object description
// p variable - Print variable
// bt - Print backtrace
// frame variable - Print local variables
// continue - Continue execution
// step - Step into
// next - Step over
// finish - Step out
import os.log
class LoggingExample {
static let logger = Logger(subsystem: "com.example.myapp", category: "network")
func demonstrateLogging() {
// Basic print
print("Basic debug message")
// Formatted print
let userName = "John"
let userAge = 25
print("User: \(userName), Age: \(userAge)")
// NSLog (includes timestamp and process info)
NSLog("NSLog message with timestamp")
// os_log (recommended for iOS 10+)
os_log("Network request started", log: .default, type: .info)
os_log("Error occurred: %@", log: .default, type: .error, "Network timeout")
// Logger (iOS 14+)
Self.logger.info("Using new Logger API")
Self.logger.error("Error: \(userAge, privacy: .public)")
// Debug-only logging
#if DEBUG
print("Debug-only message")
#endif
}
}
class MemoryDebugging {
weak var delegate: SomeDelegate?
// Memory leak example - strong reference cycle
var closure: (() -> Void)?
init() {
// This creates a retain cycle
closure = {
// self is captured strongly
self.someMethod()
}
// Correct way - weak self
closure = { [weak self] in
self?.someMethod()
}
// Or unowned self if you're sure self won't be deallocated
closure = { [unowned self] in
self.someMethod()
}
}
private func someMethod() {
print("Some method called")
}
deinit {
print("MemoryDebugging deallocated")
}
}
// Memory debugging tools in Xcode:
// - Memory graph debugger (Debug Navigator)
// - Instruments (Leaks, Allocations)
// - Static analyzer (Product -> Analyze)
class ViewDebuggingExample: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// View hierarchy debugging
// Use Debug -> View Debugging -> Capture View Hierarchy
setupComplexLayout()
}
private func setupComplexLayout() {
let containerView = UIView()
containerView.backgroundColor = .systemBackground
containerView.translatesAutoresizingMaskIntoConstraints = false
let label = UILabel()
label.text = "Debug this view"
label.backgroundColor = .systemBlue
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(containerView)
containerView.addSubview(label)
// Constraints that might cause issues
NSLayoutConstraint.activate([
containerView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
containerView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
containerView.widthAnchor.constraint(equalToConstant: 200),
containerView.heightAnchor.constraint(equalToConstant: 100),
label.centerXAnchor.constraint(equalTo: containerView.centerXAnchor),
label.centerYAnchor.constraint(equalTo: containerView.centerYAnchor)
])
}
}
// View debugging features:
// - 3D view hierarchy
// - Constraint visualization
// - View properties inspection
// - Frame and bounds information
class PerformanceExample {
func performanceOptimization() {
// CPU-intensive operation
let startTime = CFAbsoluteTimeGetCurrent()
heavyComputation()
let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
print("Time elapsed: \(timeElapsed) seconds")
}
private func heavyComputation() {
// This will show up in Time Profiler
var result = 0
for i in 0..<1000000 {
result += i * i
}
print("Computation result: \(result)")
}
// Use dispatch queues for better performance
func optimizedComputation() {
DispatchQueue.global(qos: .userInitiated).async {
self.heavyComputation()
DispatchQueue.main.async {
// Update UI on main queue
self.updateUI()
}
}
}
private func updateUI() {
// UI updates
}
}
class MemoryOptimization {
// Memory-efficient image loading
func loadImage(named: String) -> UIImage? {
guard let path = Bundle.main.path(forResource: named, ofType: "jpg"),
let image = UIImage(contentsOfFile: path) else {
return nil
}
// Resize image to reduce memory footprint
return resizeImage(image, targetSize: CGSize(width: 300, height: 300))
}
private func resizeImage(_ image: UIImage, targetSize: CGSize) -> UIImage {
let renderer = UIGraphicsImageRenderer(size: targetSize)
return renderer.image { _ in
image.draw(in: CGRect(origin: .zero, size: targetSize))
}
}
// Efficient collection handling
func processLargeDataSet() {
let largeArray = Array(1...1000000)
// Use lazy evaluation for memory efficiency
let result = largeArray
.lazy
.filter { $0 % 2 == 0 }
.map { $0 * 2 }
.prefix(100)
// Process only what's needed
for item in result {
print(item)
}
}
}
class EnergyOptimization {
private var timer: Timer?
private let locationManager = CLLocationManager()
func optimizeForBattery() {
// Use timer efficiently
startEfficientTimer()
// Optimize location usage
optimizeLocationUsage()
// Background task management
handleBackgroundTasks()
}
private func startEfficientTimer() {
// Use larger intervals when possible
timer = Timer.scheduledTimer(withTimeInterval: 60.0, repeats: true) { _ in
self.performPeriodicTask()
}
}
private func optimizeLocationUsage() {
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
locationManager.distanceFilter = 100 // Only update every 100 meters
// Use significant location changes for background
locationManager.startMonitoringSignificantLocationChanges()
}
private func handleBackgroundTasks() {
NotificationCenter.default.addObserver(
self,
selector: #selector(appDidEnterBackground),
name: UIApplication.didEnterBackgroundNotification,
object: nil
)
}
@objc private func appDidEnterBackground() {
// Stop unnecessary operations
timer?.invalidate()
timer = nil
// Reduce location accuracy
locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
}
private func performPeriodicTask() {
// Minimize work here
}
}
// Project build settings configuration
// Common Build Settings:
// - iOS Deployment Target: 14.0
// - Swift Language Version: 5.0
// - Architectures: arm64, arm64e
// - Valid Architectures: arm64, arm64e, x86_64 (for simulator)
// - Build Active Architecture Only: NO (for Release)
// Custom build configurations
#if DEBUG
let apiURL = "https://api-dev.example.com"
let logLevel = "verbose"
#elseif STAGING
let apiURL = "https://api-staging.example.com"
let logLevel = "info"
#else
let apiURL = "https://api.example.com"
let logLevel = "error"
#endif
# Custom build phase scripts
# 1. SwiftLint (Add as "Run Script Phase")
if which swiftlint >/dev/null; then
swiftlint
else
echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi
# 2. Version increment
buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${INFOPLIST_FILE}")
buildNumber=$(($buildNumber + 1))
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "${INFOPLIST_FILE}"
# 3. Copy files to bundle
cp "${SRCROOT}/Config/${CONFIGURATION}.plist" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/Config.plist"
// Info.plist configuration per environment
// Development.plist, Staging.plist, Production.plist
class EnvironmentConfig {
static let shared = EnvironmentConfig()
private init() {}
var apiURL: String {
guard let path = Bundle.main.path(forResource: "Config", ofType: "plist"),
let plist = NSDictionary(contentsOfFile: path),
let url = plist["APIBaseURL"] as? String else {
fatalError("Config.plist not found or APIBaseURL not set")
}
return url
}
var isDebugMode: Bool {
#if DEBUG
return true
#else
return false
#endif
}
}
import XCTest
@testable import MyApp
class CalculatorTests: XCTestCase {
var calculator: Calculator!
override func setUpWithError() throws {
try super.setUpWithError()
calculator = Calculator()
}
override func tearDownWithError() throws {
calculator = nil
try super.tearDownWithError()
}
func testAddition() {
// Given
let a = 5
let b = 3
// When
let result = calculator.add(a, b)
// Then
XCTAssertEqual(result, 8, "Addition should return correct sum")
}
func testDivisionByZero() {
// Given
let a = 10
let b = 0
// When/Then
XCTAssertThrowsError(try calculator.divide(a, by: b)) { error in
XCTAssertTrue(error is CalculatorError)
}
}
func testAsyncOperation() async throws {
// Given
let expectedResult = "success"
// When
let result = await calculator.performAsyncOperation()
// Then
XCTAssertEqual(result, expectedResult)
}
func testPerformanceOfHeavyOperation() {
measure {
calculator.performHeavyOperation()
}
}
}
// Mock objects for testing
class MockNetworkService: NetworkServiceProtocol {
var shouldReturnError = false
var mockResponse: Data?
func fetchData(completion: @escaping (Result<Data, Error>) -> Void) {
if shouldReturnError {
completion(.failure(NetworkError.requestFailed))
} else {
completion(.success(mockResponse ?? Data()))
}
}
}
import XCTest
class MyAppUITests: XCTestCase {
var app: XCUIApplication!
override func setUpWithError() throws {
try super.setUpWithError()
continueAfterFailure = false
app = XCUIApplication()
app.launch()
}
override func tearDownWithError() throws {
app = nil
try super.tearDownWithError()
}
func testLoginFlow() throws {
// Navigate to login screen
let loginButton = app.buttons["loginButton"]
XCTAssertTrue(loginButton.exists)
loginButton.tap()
// Enter credentials
let usernameField = app.textFields["usernameField"]
usernameField.tap()
usernameField.typeText("[email protected]")
let passwordField = app.secureTextFields["passwordField"]
passwordField.tap()
passwordField.typeText("password123")
// Submit form
let submitButton = app.buttons["submitButton"]
submitButton.tap()
// Verify successful login
let welcomeText = app.staticTexts["welcomeText"]
XCTAssertTrue(welcomeText.waitForExistence(timeout: 5))
XCTAssertEqual(welcomeText.label, "Welcome, Test User!")
}
func testTableViewInteraction() throws {
let table = app.tables["itemsTable"]
XCTAssertTrue(table.exists)
// Scroll to find cell
let cell = table.cells.element(boundBy: 0)
cell.swipeLeft()
// Tap delete button
let deleteButton = table.buttons["Delete"]
deleteButton.tap()
// Verify deletion
XCTAssertFalse(cell.exists)
}
func testScreenshotCapture() {
let screenshot = app.screenshot()
let attachment = XCTAttachment(screenshot: screenshot)
attachment.lifetime = .keepAlways
add(attachment)
}
}
class PerformanceTests: XCTestCase {
func testLaunchPerformance() throws {
if #available(iOS 13.0, *) {
measure(metrics: [XCTApplicationLaunchMetric()]) {
XCUIApplication().launch()
}
}
}
func testScrollPerformance() throws {
let app = XCUIApplication()
app.launch()
let table = app.tables["itemsTable"]
measure(metrics: [XCTOSSignpostMetric.scrollingAndDecelerationMetric]) {
table.swipeUp(velocity: .fast)
table.swipeDown(velocity: .fast)
}
}
func testMemoryPerformance() throws {
measure(metrics: [XCTMemoryMetric()]) {
// Perform memory-intensive operation
let largeArray = Array(0..<1000000)
_ = largeArray.map { $0 * 2 }
}
}
}
// Automatic signing configuration
// Project Settings -> Signing & Capabilities
// - Team: Your development team
// - Provisioning Profile: Automatic
// - Signing Certificate: Apple Development
// Manual signing
// 1. Create certificates in Apple Developer Portal
// 2. Create App ID
// 3. Create provisioning profile
// 4. Download and install profile
// 5. Configure in Xcode project settings
// Archive and upload process
// 1. Product -> Archive
// 2. Window -> Organizer
// 3. Select archive -> Distribute App
// 4. App Store Connect
// 5. Upload
// App Store Connect metadata
// - App name, description, keywords
// - Screenshots for all device types
// - App privacy information
// - Pricing and availability
// - App Review information
// TestFlight distribution
class TestFlightManager {
static func prepareForTestFlight() {
// Ensure proper build configuration
// 1. Increment build number
// 2. Test on device
// 3. Archive with distribution certificate
// 4. Upload to App Store Connect
// 5. Add beta testers
}
static func handleTestFlightFeedback() {
// Process feedback from TestFlight
// 1. Review crash logs
// 2. Analyze usage metrics
// 3. Address reported issues
// 4. Iterate and release new beta
}
}
class AccessibilityExample: UIViewController {
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var actionButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
setupAccessibility()
}
private func setupAccessibility() {
// Image accessibility
imageView.isAccessibilityElement = true
imageView.accessibilityLabel = "Profile photo"
imageView.accessibilityTraits = .image
// Label accessibility
titleLabel.accessibilityLabel = "User name: \(titleLabel.text ?? "")"
// Button accessibility
actionButton.accessibilityLabel = "Edit profile"
actionButton.accessibilityHint = "Double tap to edit your profile information"
actionButton.accessibilityTraits = .button
// Custom accessibility action
let customAction = UIAccessibilityCustomAction(
name: "Share profile",
target: self,
selector: #selector(shareProfile)
)
actionButton.accessibilityCustomActions = [customAction]
// Accessibility grouping
let groupedElements = [titleLabel!, actionButton!]
view.shouldGroupAccessibilityChildren = true
}
@objc private func shareProfile() -> Bool {
// Implement share functionality
print("Profile shared")
return true
}
}
class DynamicTypeExample: UIViewController {
@IBOutlet weak var headlineLabel: UILabel!
@IBOutlet weak var bodyLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
setupDynamicType()
// Listen for font size changes
NotificationCenter.default.addObserver(
self,
selector: #selector(fontSizeDidChange),
name: UIContentSizeCategory.didChangeNotification,
object: nil
)
}
private func setupDynamicType() {
// Use preferred fonts
headlineLabel.font = UIFont.preferredFont(forTextStyle: .headline)
bodyLabel.font = UIFont.preferredFont(forTextStyle: .body)
// Enable automatic font adjustment
headlineLabel.adjustsFontForContentSizeCategory = true
bodyLabel.adjustsFontForContentSizeCategory = true
// Custom font with dynamic type
let customFont = UIFont(name: "CustomFont-Bold", size: 18) ?? UIFont.systemFont(ofSize: 18)
let scaledFont = UIFontMetrics(forTextStyle: .headline).scaledFont(for: customFont)
headlineLabel.font = scaledFont
}
@objc private func fontSizeDidChange() {
setupDynamicType()
view.setNeedsLayout()
}
deinit {
NotificationCenter.default.removeObserver(self)
}
}
// Xcode Source Control features:
// 1. Source Control Navigator (Cmd+2)
// 2. Commit changes (Cmd+Option+C)
// 3. Compare files
// 4. View history and blame
// 5. Branch management
// 6. Merge and resolve conflicts
// .gitignore for iOS projects
/*
# Xcode
*.xcodeproj/*
!*.xcodeproj/project.pbxproj
!*.xcodeproj/xcshareddata/
!*.xcworkspace/contents.xcworkspacedata
# Build products
build/
DerivedData/
*.hmap
*.ipa
*.dSYM.zip
*.dSYM
# CocoaPods
Pods/
# Carthage
Carthage/Checkouts
Carthage/Build/
# Swift Package Manager
.swiftpm/
Packages/
Package.resolved
# IDEs
.vscode/
.idea/
# OS generated files
.DS_Store
Thumbs.db
*/
class CodeReviewBestPractices {
// MARK: - Good practices for reviewable code
/// Clear method documentation
/// - Parameters:
/// - user: The user to process
/// - completion: Callback with result
func processUser(_ user: User, completion: @escaping (Result<User, Error>) -> Void) {
// Implementation with clear intent
validateUser(user) { [weak self] isValid in
guard isValid else {
completion(.failure(ValidationError.invalidUser))
return
}
self?.saveUser(user, completion: completion)
}
}
private func validateUser(_ user: User, completion: @escaping (Bool) -> Void) {
// Validation logic
completion(!user.email.isEmpty && user.age >= 0)
}
private func saveUser(_ user: User, completion: @escaping (Result<User, Error>) -> Void) {
// Save logic
completion(.success(user))
}
}
class LaunchOptimization {
// Optimize app launch time
static func optimizeAppLaunch() {
// 1. Minimize work in application:didFinishLaunchingWithOptions:
// 2. Use lazy loading for non-critical resources
// 3. Defer heavy initializations
// 4. Optimize image loading
// 5. Reduce dynamic library loading
}
// Lazy initialization
lazy var expensiveResource: ExpensiveResource = {
return ExpensiveResource()
}()
// Background initialization
func initializeInBackground() {
DispatchQueue.global(qos: .utility).async {
// Heavy initialization work
let resource = ExpensiveResource()
DispatchQueue.main.async {
// Update UI with initialized resource
self.updateUI(with: resource)
}
}
}
private func updateUI(with resource: ExpensiveResource) {
// Update UI
}
}
class MemoryManagement {
// Use weak references to avoid retain cycles
weak var delegate: SomeDelegate?
// Proper closure handling
func setupClosures() {
someAsyncOperation { [weak self] result in
self?.handleResult(result)
}
// Use unowned when self is guaranteed to exist
someOtherOperation { [unowned self] in
self.handleImmediate()
}
}
// Memory-efficient image handling
func loadAndDisplayImage(at url: URL) {
URLSession.shared.dataTask(with: url) { [weak self] data, _, _ in
guard let data = data,
let image = UIImage(data: data) else { return }
DispatchQueue.main.async {
// Resize image if needed to save memory
let resizedImage = self?.resizeImage(image, to: CGSize(width: 200, height: 200))
self?.imageView.image = resizedImage
}
}.resume()
}
private func resizeImage(_ image: UIImage, to size: CGSize) -> UIImage {
UIGraphicsImageRenderer(size: size).image { _ in
image.draw(in: CGRect(origin: .zero, size: size))
}
}
deinit {
// Cleanup resources
print("MemoryManagement deallocated")
}
}