1. Swift Mastery
Swift is the core programming language for iOS development. A strong iOS developer should deeply understand Swift fundamentals, not only how to write code.
Variables and Constants
Swift uses var for changeable values and let for fixed values.
1
2
3
4
5
6
7
8
9
| import Foundation
let appName = "My iOS App" // Constant value
var downloadCount = 100 // Variable value
downloadCount = 150
print(appName)
print(downloadCount)
|
Struct
A struct is a value type. It is commonly used for models in Swift.
1
2
3
4
5
6
7
8
9
| struct User {
let id: Int
var name: String
var isPremium: Bool
}
let user = User(id: 1, name: "Tawhid", isPremium: true)
print(user.name)
|
Class
A class is a reference type. It is useful when you need shared object references.
1
2
3
4
5
6
7
8
9
10
11
12
| class UserManager {
var username: String = "Guest"
func updateName(_ name: String) {
username = name
}
}
let manager = UserManager()
manager.updateName("Tawhid")
print(manager.username)
|
Value Type vs Reference Type
Structs are copied when assigned. Classes share the same reference.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| struct ProfileStruct {
var name: String
}
class ProfileClass {
var name: String
init(name: String) {
self.name = name
}
}
// Struct example
var profile1 = ProfileStruct(name: "A")
var profile2 = profile1
profile2.name = "B"
print(profile1.name) // A
print(profile2.name) // B
// Class example
let classProfile1 = ProfileClass(name: "A")
let classProfile2 = classProfile1
classProfile2.name = "B"
print(classProfile1.name) // B
print(classProfile2.name) // B
|
Optionals
Optionals are used when a value may or may not exist.
1
2
3
4
5
6
7
| var username: String? = "Tawhid"
if let name = username {
print("Username is \(name)")
} else {
print("Username not found")
}
|
Guard Let
guard let is commonly used to safely unwrap optionals and return early.
1
2
3
4
5
6
7
8
9
10
11
| func showUserName(_ name: String?) {
guard let name = name else {
print("No name found")
return
}
print("User name is \(name)")
}
showUserName("Tawhid")
showUserName(nil)
|
Closures
Closures are blocks of code that can be passed around like functions.
1
2
3
4
5
| let greeting: (String) -> String = { name in
return "Hello, \(name)"
}
print(greeting("Tawhid"))
|
Protocols
Protocols define rules that a class, struct, or enum must follow.
1
2
3
4
5
6
7
8
9
10
11
12
| protocol Downloadable {
func download()
}
struct VideoDownloader: Downloadable {
func download() {
print("Video download started")
}
}
let downloader = VideoDownloader()
downloader.download()
|
Extensions
Extensions allow you to add new functionality to existing types.
1
2
3
4
5
6
7
8
| extension String {
func addWelcomeText() -> String {
return "Welcome, \(self)"
}
}
let name = "Tawhid"
print(name.addWelcomeText())
|
Generics
Generics allow you to write reusable and flexible code.
1
2
3
4
5
6
7
| func printValue<T>(_ value: T) {
print(value)
}
printValue("Hello")
printValue(100)
printValue(true)
|
Error Handling
Swift uses do, try, and catch for error handling.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| enum LoginError: Error {
case invalidPassword
case userNotFound
}
func login(password: String) throws {
if password != "123456" {
throw LoginError.invalidPassword
}
print("Login successful")
}
do {
try login(password: "wrong")
} catch {
print("Login failed: \(error)")
}
|
Async/Await
async/await is used for modern asynchronous code.
1
2
3
4
5
6
7
8
9
10
| import Foundation
func fetchUserName() async -> String {
return "Tawhid"
}
Task {
let name = await fetchUserName()
print(name)
}
|
ARC and Memory Management
Swift uses ARC, which means Automatic Reference Counting. It automatically manages memory for class instances.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| class User {
let name: String
init(name: String) {
self.name = name
print("\(name) created")
}
deinit {
print("\(name) removed from memory")
}
}
var user: User? = User(name: "Tawhid")
user = nil
|
2. SwiftUI
SwiftUI is Apple’s modern declarative UI framework. It allows developers to build user interfaces with less code and cleaner structure.
Layout
SwiftUI supports layout systems based on stacks such as VStack, HStack, and ZStack. This system simplifies the alignment of components in the current view. It also allows nesting of views.
1
2
3
4
5
6
7
8
9
10
11
12
13
| import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Text("TutorialsPoint")
.font(.title)
Text("Learn SwiftUI")
.font(.subheadline)
}
}
}
|
HStack
HStack arranges views horizontally.
1
2
3
4
5
6
7
8
9
10
11
12
| import SwiftUI
struct ContentView: View {
var body: some View {
HStack {
Image(systemName: "star.fill")
Text("Premium User")
}
.font(.title)
.padding()
}
}
|
ZStack
ZStack places views on top of each other.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| import SwiftUI
struct ContentView: View {
var body: some View {
ZStack {
Color.blue
.ignoresSafeArea()
Text("Welcome")
.font(.largeTitle)
.foregroundStyle(.white)
}
}
}
|
State Management with @State
@State is used when a view owns a simple value that can change.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| import SwiftUI
struct CounterView: View {
@State private var count = 0
var body: some View {
VStack {
Text("Count: \(count)")
.font(.title)
Button("Increase") {
count += 1
}
}
.padding()
}
}
|
Binding with @Binding
@Binding is used to pass a mutable value from parent view to child view.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| import SwiftUI
struct ParentView: View {
@State private var isOn = false
var body: some View {
ToggleChildView(isOn: $isOn)
}
}
struct ToggleChildView: View {
@Binding var isOn: Bool
var body: some View {
Toggle("Enable Feature", isOn: $isOn)
.padding()
}
}
|
ObservableObject
ObservableObject is used when a class manages state for a view.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| import SwiftUI
class ProfileViewModel: ObservableObject {
@Published var username = "Guest"
func updateName() {
username = "Tawhid"
}
}
struct ProfileView: View {
@StateObject private var viewModel = ProfileViewModel()
var body: some View {
VStack {
Text(viewModel.username)
.font(.title)
Button("Update Name") {
viewModel.updateName()
}
}
}
}
|
Navigation
SwiftUI uses NavigationStack for screen navigation.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| import SwiftUI
struct HomeView: View {
var body: some View {
NavigationStack {
VStack {
NavigationLink("Go to Details") {
DetailsView()
}
}
.navigationTitle("Home")
}
}
}
struct DetailsView: View {
var body: some View {
Text("Details Screen")
.navigationTitle("Details")
}
}
|
List
List is used to show scrollable rows.
1
2
3
4
5
6
7
8
9
10
11
12
| import SwiftUI
struct UserListView: View {
let users = ["Tawhid", "Alex", "John", "Sarah"]
var body: some View {
List(users, id: \.self) { user in
Text(user)
}
.navigationTitle("Users")
}
}
|
LazyVStack
LazyVStack loads content efficiently when scrolling.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| import SwiftUI
struct LazyListView: View {
var body: some View {
ScrollView {
LazyVStack {
ForEach(1...100, id: \.self) { item in
Text("Item \(item)")
.padding()
}
}
}
}
}
|
Sheet
A sheet is used to show a modal screen.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| import SwiftUI
struct SheetExampleView: View {
@State private var showSheet = false
var body: some View {
Button("Open Sheet") {
showSheet = true
}
.sheet(isPresented: $showSheet) {
Text("This is a sheet")
.font(.title)
.padding()
}
}
}
|
Animation
SwiftUI makes animations simple with withAnimation.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| import SwiftUI
struct AnimationView: View {
@State private var isExpanded = false
var body: some View {
VStack {
RoundedRectangle(cornerRadius: 20)
.frame(width: isExpanded ? 250 : 120, height: 120)
Button("Animate") {
withAnimation {
isExpanded.toggle()
}
}
}
}
}
|
Gesture
Gestures allow users to interact with views using touch.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| import SwiftUI
struct GestureView: View {
@State private var scale = 1.0
var body: some View {
Text("Tap Me")
.font(.title)
.scaleEffect(scale)
.onTapGesture {
scale += 0.2
}
}
}
|
Dark Mode Support
SwiftUI automatically supports dark mode, but we can customize colors.
1
2
3
4
5
6
7
8
9
10
| import SwiftUI
struct DarkModeView: View {
var body: some View {
Text("Adaptive Color")
.padding()
.background(Color(.systemBackground))
.foregroundStyle(Color(.label))
}
}
|
Accessibility
Accessibility helps users with visual, hearing, or physical limitations use the app.
1
2
3
4
5
6
7
8
9
10
11
12
13
| import SwiftUI
struct AccessibilityView: View {
var body: some View {
Button {
print("Favorite tapped")
} label: {
Image(systemName: "heart.fill")
}
.accessibilityLabel("Add to favorites")
.accessibilityHint("Double tap to save this item")
}
}
|
3. UIKit
UIKit is Apple’s older but still very powerful UI framework. Many production apps still use UIKit, so a professional iOS developer should understand it.
UIViewController
UIViewController controls a screen in UIKit.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| import UIKit
class HomeViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
let label = UILabel()
label.text = "Hello UIKit"
label.font = .systemFont(ofSize: 24)
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
label.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
}
|
UITableView
UITableView is used to display scrollable lists in UIKit.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| import UIKit
class UserTableViewController: UITableViewController {
let users = ["Tawhid", "Alex", "John"]
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return users.count
}
override func tableView(
_ tableView: UITableView,
cellForRowAt indexPath: IndexPath
) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = users[indexPath.row]
return cell
}
}
|
SwiftUI and UIKit Interoperability
SwiftUI can show UIKit views using UIViewControllerRepresentable.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| import SwiftUI
import UIKit
struct UIKitLabelView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> UIViewController {
let controller = UIViewController()
controller.view.backgroundColor = .systemBackground
let label = UILabel()
label.text = "UIKit inside SwiftUI"
label.translatesAutoresizingMaskIntoConstraints = false
controller.view.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: controller.view.centerXAnchor),
label.centerYAnchor.constraint(equalTo: controller.view.centerYAnchor)
])
return controller
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
}
|
4. App Architecture
Architecture helps you build scalable, testable, and maintainable apps.
MVVM
MVVM means Model, View, ViewModel.
- Model contains data.
- View displays UI.
- ViewModel handles business logic and state.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| import SwiftUI
struct Product: Identifiable {
let id = UUID()
let name: String
let price: Double
}
class ProductViewModel: ObservableObject {
@Published var products: [Product] = []
func loadProducts() {
products = [
Product(name: "Premium Plan", price: 9.99),
Product(name: "Lifetime Plan", price: 49.99)
]
}
}
struct ProductView: View {
@StateObject private var viewModel = ProductViewModel()
var body: some View {
List(viewModel.products) { product in
VStack(alignment: .leading) {
Text(product.name)
Text("$\(product.price)")
.font(.caption)
}
}
.onAppear {
viewModel.loadProducts()
}
}
}
|
Repository Pattern
Repository pattern separates data source logic from UI logic.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
| import Foundation
struct UserModel: Codable {
let id: Int
let name: String
}
protocol UserRepositoryProtocol {
func getUsers() async throws -> [UserModel]
}
class UserRepository: UserRepositoryProtocol {
func getUsers() async throws -> [UserModel] {
return [
UserModel(id: 1, name: "Tawhid"),
UserModel(id: 2, name: "John")
]
}
}
class UserViewModel: ObservableObject {
@Published var users: [UserModel] = []
private let repository: UserRepositoryProtocol
init(repository: UserRepositoryProtocol = UserRepository()) {
self.repository = repository
}
func loadUsers() async {
do {
users = try await repository.getUsers()
} catch {
print("Failed to load users")
}
}
}
|
Dependency Injection
Dependency Injection means passing dependencies from outside instead of creating them inside the class.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| protocol PaymentService {
func pay(amount: Double)
}
class StripePaymentService: PaymentService {
func pay(amount: Double) {
print("Paid \(amount) using Stripe")
}
}
class CheckoutViewModel {
private let paymentService: PaymentService
init(paymentService: PaymentService) {
self.paymentService = paymentService
}
func checkout() {
paymentService.pay(amount: 19.99)
}
}
let viewModel = CheckoutViewModel(paymentService: StripePaymentService())
viewModel.checkout()
|
5. Networking and APIs
Most real apps communicate with backend APIs. A professional iOS developer must know how to call APIs, parse JSON, handle errors, and manage authentication.
URLSession GET Request
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| import Foundation
struct Post: Codable {
let id: Int
let title: String
}
func fetchPosts() async throws -> [Post] {
let url = URL(string: "https://jsonplaceholder.typicode.com/posts")!
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
throw URLError(.badServerResponse)
}
return try JSONDecoder().decode([Post].self, from: data)
}
Task {
do {
let posts = try await fetchPosts()
print(posts.first?.title ?? "No title")
} catch {
print("API error: \(error)")
}
}
|
POST Request
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| import Foundation
struct LoginRequest: Codable {
let email: String
let password: String
}
struct LoginResponse: Codable {
let token: String
}
func login(email: String, password: String) async throws -> LoginResponse {
let url = URL(string: "https://example.com/api/login")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let body = LoginRequest(email: email, password: password)
request.httpBody = try JSONEncoder().encode(body)
let (data, _) = try await URLSession.shared.data(for: request)
return try JSONDecoder().decode(LoginResponse.self, from: data)
}
|
1
2
3
4
5
6
7
8
9
10
11
12
| import Foundation
func fetchProfile(token: String) async throws {
let url = URL(string: "https://example.com/api/profile")!
var request = URLRequest(url: url)
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
let (_, response) = try await URLSession.shared.data(for: request)
print(response)
}
|
6. Local Storage and Database
iOS apps need local storage for settings, cache, user sessions, and offline data.
UserDefaults
Use UserDefaults for small simple values.
1
2
3
4
5
6
7
| import Foundation
UserDefaults.standard.set(true, forKey: "isPremiumUser")
let isPremium = UserDefaults.standard.bool(forKey: "isPremiumUser")
print(isPremium)
|
AppStorage
@AppStorage is a SwiftUI-friendly wrapper around UserDefaults.
1
2
3
4
5
6
7
8
9
10
| import SwiftUI
struct SettingsView: View {
@AppStorage("isDarkMode") private var isDarkMode = false
var body: some View {
Toggle("Dark Mode", isOn: $isDarkMode)
.padding()
}
}
|
Keychain
Use Keychain for sensitive data like tokens and passwords.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| import Foundation
import Security
class KeychainHelper {
static func saveToken(_ token: String) {
let data = Data(token.utf8)
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: "authToken",
kSecValueData as String: data
]
SecItemDelete(query as CFDictionary)
SecItemAdd(query as CFDictionary, nil)
}
}
|
FileManager
Use FileManager to save files locally.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| import Foundation
func saveTextFile() {
let text = "Hello iOS Developer"
let fileURL = FileManager.default.urls(
for: .documentDirectory,
in: .userDomainMask
)[0].appendingPathComponent("note.txt")
do {
try text.write(to: fileURL, atomically: true, encoding: .utf8)
print("File saved at \(fileURL)")
} catch {
print("Failed to save file")
}
}
|
SwiftData
SwiftData is Apple’s modern persistence framework.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| import SwiftUI
import SwiftData
@Model
class Note {
var title: String
init(title: String) {
self.title = title
}
}
struct NotesView: View {
@Environment(\.modelContext) private var context
@Query private var notes: [Note]
var body: some View {
List(notes) { note in
Text(note.title)
}
.toolbar {
Button("Add") {
let note = Note(title: "New Note")
context.insert(note)
}
}
}
}
|
Outstanding iOS developers know how to make apps fast, smooth, and memory-efficient.
Task
Task is used to run asynchronous work.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| import SwiftUI
struct TaskExampleView: View {
@State private var username = "Loading..."
var body: some View {
Text(username)
.task {
username = await loadUser()
}
}
func loadUser() async -> String {
return "Tawhid"
}
}
|
MainActor
UI updates should happen on the main thread. @MainActor guarantees this.
1
2
3
4
5
6
7
8
9
10
| import Foundation
@MainActor
class DashboardViewModel: ObservableObject {
@Published var title = "Dashboard"
func updateTitle() {
title = "Updated Dashboard"
}
}
|
Actor
Actors protect shared mutable state from data races.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| actor DownloadCounter {
private var count = 0
func increment() {
count += 1
}
func getCount() -> Int {
return count
}
}
let counter = DownloadCounter()
Task {
await counter.increment()
let count = await counter.getCount()
print(count)
}
|
Avoid Heavy Work on Main Thread
Heavy work should run in the background to avoid UI freezing.
1
2
3
4
5
6
7
8
9
10
| import Foundation
func processLargeData() async {
let result = await Task.detached {
// Heavy background work
return (1...1_000_000).reduce(0, +)
}.value
print(result)
}
|
Retain Cycle Prevention
Use [weak self] to avoid memory leaks inside closures.
1
2
3
4
5
6
7
8
9
10
11
12
13
| class DownloadManager {
var onComplete: (() -> Void)?
func startDownload() {
onComplete = { [weak self] in
self?.showSuccess()
}
}
func showSuccess() {
print("Download completed")
}
}
|
8. iOS System Features
Professional apps often use native iOS capabilities such as camera, photos, notifications, background tasks, widgets, and deep links.
Local Notification
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| import UserNotifications
func requestNotificationPermission() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
print("Permission granted: \(granted)")
}
}
func scheduleNotification() {
let content = UNMutableNotificationContent()
content.title = "Task Complete"
content.body = "Your file has been processed successfully."
content.sound = .default
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
let request = UNNotificationRequest(
identifier: UUID().uuidString,
content: content,
trigger: trigger
)
UNUserNotificationCenter.current().add(request)
}
|
Photo Picker
1
2
3
4
5
6
7
8
9
10
11
| import SwiftUI
import PhotosUI
struct PhotoPickerView: View {
@State private var selectedItem: PhotosPickerItem?
var body: some View {
PhotosPicker("Select Image", selection: $selectedItem, matching: .images)
.padding()
}
}
|
Share Sheet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| import SwiftUI
import UIKit
struct ShareSheet: UIViewControllerRepresentable {
let items: [Any]
func makeUIViewController(context: Context) -> UIActivityViewController {
UIActivityViewController(activityItems: items, applicationActivities: nil)
}
func updateUIViewController(_ uiViewController: UIActivityViewController, context: Context) {}
}
struct ShareExampleView: View {
@State private var showShareSheet = false
var body: some View {
Button("Share") {
showShareSheet = true
}
.sheet(isPresented: $showShareSheet) {
ShareSheet(items: ["Hello from my iOS app"])
}
}
}
|
Deep Link Handling
1
2
3
4
5
6
7
8
9
10
11
12
13
| import SwiftUI
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL { url in
print("Opened URL: \(url)")
}
}
}
}
|
9. Security
Security is very important in production iOS apps. Sensitive data should never be stored in plain text.
Secure Token Storage
Use Keychain instead of UserDefaults for tokens.
1
2
3
4
5
| // Good
KeychainHelper.saveToken("secure-token")
// Bad
UserDefaults.standard.set("secure-token", forKey: "token")
|
App Transport Security
Always use HTTPS API URLs.
1
| let secureURL = URL(string: "https://example.com/api/users")!
|
Simple Hash Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| import Foundation
import CryptoKit
func sha256(_ text: String) -> String {
let data = Data(text.utf8)
let hash = SHA256.hash(data: data)
return hash.compactMap {
String(format: "%02x", $0)
}.joined()
}
let result = sha256("Hello")
print(result)
|
Secure API Request Idea
For high-security apps, you can sign requests with timestamp and nonce.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| import Foundation
struct SecureRequestPayload: Codable {
let path: String
let timestamp: Int
let nonce: String
let body: String
}
let payload = SecureRequestPayload(
path: "/api/order",
timestamp: Int(Date().timeIntervalSince1970),
nonce: UUID().uuidString,
body: "{\"order_id\":123}"
)
print(payload)
|
10. App Store and Release Engineering
A real iOS developer should understand how to prepare, test, and release apps.
Important Release Skills
You should learn:
- Apple Developer Account
- Bundle Identifier
- Certificates
- Provisioning Profiles
- App Signing
- TestFlight
- App Store Connect
- App Review Guidelines
- App Privacy Labels
- Crash Reporting
- Analytics
- CI/CD
- Fastlane
App Version Example
1
2
3
4
5
6
7
8
9
| import Foundation
func printAppVersion() {
let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
let build = Bundle.main.infoDictionary?["CFBundleVersion"] as? String
print("Version: \(version ?? "Unknown")")
print("Build: \(build ?? "Unknown")")
}
|
Environment Configuration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| import Foundation
enum AppEnvironment {
case development
case staging
case production
var baseURL: String {
switch self {
case .development:
return "https://dev.example.com"
case .staging:
return "https://staging.example.com"
case .production:
return "https://api.example.com"
}
}
}
let environment = AppEnvironment.staging
print(environment.baseURL)
|
11. Debugging Skills
Outstanding developers are strong debuggers. They know how to find problems quickly.
Print Debugging
1
2
| let username = "Tawhid"
print("Current username: \(username)")
|
Debug Only Code
1
2
3
| #if DEBUG
print("This log only appears in debug mode")
#endif
|
Custom Logger
1
2
3
4
5
6
7
8
9
10
11
| import Foundation
enum AppLogger {
static func log(_ message: String) {
#if DEBUG
print("DEBUG LOG:", message)
#endif
}
}
AppLogger.log("User opened home screen")
|
You should master:
- Xcode Breakpoints
- LLDB Console
- Memory Graph Debugger
- Instruments
- Network Logs
- Console Logs
- Crash Logs
- View Hierarchy Debugger
12. Testing
Testing helps you build stable and professional apps.
Unit Test
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| import XCTest
struct Calculator {
func add(_ a: Int, _ b: Int) -> Int {
return a + b
}
}
final class CalculatorTests: XCTestCase {
func testAdd() {
let calculator = Calculator()
let result = calculator.add(2, 3)
XCTAssertEqual(result, 5)
}
}
|
ViewModel Test
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| import XCTest
import Foundation
class LoginViewModel {
func isValidEmail(_ email: String) -> Bool {
return email.contains("@") && email.contains(".")
}
}
final class LoginViewModelTests: XCTestCase {
func testValidEmail() {
let viewModel = LoginViewModel()
XCTAssertTrue(viewModel.isValidEmail("test@example.com"))
}
func testInvalidEmail() {
let viewModel = LoginViewModel()
XCTAssertFalse(viewModel.isValidEmail("wrong-email"))
}
}
|
Mock Repository
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| import XCTest
protocol ProductRepositoryProtocol {
func getProducts() -> [String]
}
class MockProductRepository: ProductRepositoryProtocol {
func getProducts() -> [String] {
return ["Product A", "Product B"]
}
}
class ProductListViewModel {
private let repository: ProductRepositoryProtocol
init(repository: ProductRepositoryProtocol) {
self.repository = repository
}
func loadProducts() -> [String] {
return repository.getProducts()
}
}
final class ProductListViewModelTests: XCTestCase {
func testLoadProducts() {
let repository = MockProductRepository()
let viewModel = ProductListViewModel(repository: repository)
let products = viewModel.loadProducts()
XCTAssertEqual(products.count, 2)
}
}
|
13. Product and UX Thinking
A top iOS developer does not only write code. They also understand user experience, app flow, accessibility, and Apple design quality.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| import SwiftUI
struct PrimaryButton: View {
let title: String
let action: () -> Void
var body: some View {
Button(action: action) {
Text(title)
.font(.headline)
.frame(maxWidth: .infinity)
.padding()
.background(Color.blue)
.foregroundStyle(.white)
.clipShape(RoundedRectangle(cornerRadius: 14))
}
.padding(.horizontal)
}
}
|
Empty State UI
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| import SwiftUI
struct EmptyStateView: View {
var body: some View {
VStack(spacing: 12) {
Image(systemName: "tray")
.font(.largeTitle)
Text("No Files Yet")
.font(.title2)
.bold()
Text("Your scanned files will appear here after you create them.")
.font(.body)
.foregroundStyle(.secondary)
.multilineTextAlignment(.center)
}
.padding()
}
}
|
Loading State
1
2
3
4
5
6
7
8
9
10
11
12
13
| import SwiftUI
struct LoadingView: View {
var body: some View {
VStack(spacing: 12) {
ProgressView()
Text("Processing...")
.foregroundStyle(.secondary)
}
.padding()
}
}
|
Error State
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| import SwiftUI
struct ErrorStateView: View {
let message: String
var body: some View {
VStack(spacing: 12) {
Image(systemName: "exclamationmark.triangle")
.font(.largeTitle)
.foregroundStyle(.orange)
Text("Something went wrong")
.font(.headline)
Text(message)
.font(.body)
.foregroundStyle(.secondary)
.multilineTextAlignment(.center)
}
.padding()
}
}
|
14. Advanced iOS Topics
After learning the core skills, you can move to advanced frameworks and high-value app features.
AVFoundation
AVFoundation is used for audio and video features.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| import AVFoundation
class AudioPlayerManager {
private var player: AVAudioPlayer?
func playSound(url: URL) {
do {
player = try AVAudioPlayer(contentsOf: url)
player?.play()
} catch {
print("Failed to play audio")
}
}
}
|
Vision Framework
Vision can be used for image analysis, OCR, face detection, and object detection.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| import Vision
import UIKit
func recognizeText(from image: UIImage) {
guard let cgImage = image.cgImage else { return }
let request = VNRecognizeTextRequest { request, error in
guard let observations = request.results as? [VNRecognizedTextObservation] else {
return
}
for observation in observations {
let text = observation.topCandidates(1).first?.string ?? ""
print(text)
}
}
let handler = VNImageRequestHandler(cgImage: cgImage)
do {
try handler.perform([request])
} catch {
print("Text recognition failed")
}
}
|
CoreML
CoreML is used to run machine learning models on-device.
1
2
3
4
5
6
7
8
9
10
11
| import CoreML
func loadModel() {
do {
// Replace "MyModel" with your generated CoreML model class
// let model = try MyModel(configuration: MLModelConfiguration())
print("Model loaded successfully")
} catch {
print("Failed to load model")
}
}
|
Widgets show app information on the home screen.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| import WidgetKit
import SwiftUI
struct SimpleEntry: TimelineEntry {
let date: Date
let title: String
}
struct SimpleWidgetView: View {
var entry: SimpleEntry
var body: some View {
Text(entry.title)
.font(.headline)
.padding()
}
}
|
App Intents
App Intents allow the system, Siri, and Shortcuts to interact with your app.
1
2
3
4
5
6
7
8
9
| import AppIntents
struct OpenScannerIntent: AppIntent {
static var title: LocalizedStringResource = "Open Scanner"
func perform() async throws -> some IntentResult {
return .result()
}
}
|
15. Build Real Apps
The fastest way to become an outstanding iOS developer is to build real apps.
You should build apps that include:
- Authentication
- API calling
- Local database
- File handling
- Payment flow
- Subscription screen
- Notifications
- Image picker
- Camera
- SwiftUI navigation
- MVVM architecture
- Error handling
- Loading states
- Offline support
Mini Project Example: Notes App Structure
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
| import SwiftUI
struct NoteItem: Identifiable {
let id = UUID()
var title: String
var description: String
}
class NotesViewModel: ObservableObject {
@Published var notes: [NoteItem] = []
func addNote(title: String, description: String) {
let note = NoteItem(title: title, description: description)
notes.append(note)
}
func deleteNote(at offsets: IndexSet) {
notes.remove(atOffsets: offsets)
}
}
struct NotesAppView: View {
@StateObject private var viewModel = NotesViewModel()
@State private var title = ""
@State private var description = ""
var body: some View {
NavigationStack {
VStack {
TextField("Title", text: $title)
.textFieldStyle(.roundedBorder)
TextField("Description", text: $description)
.textFieldStyle(.roundedBorder)
Button("Add Note") {
viewModel.addNote(title: title, description: description)
title = ""
description = ""
}
List {
ForEach(viewModel.notes) { note in
VStack(alignment: .leading) {
Text(note.title)
.font(.headline)
Text(note.description)
.font(.caption)
.foregroundStyle(.secondary)
}
}
.onDelete(perform: viewModel.deleteNote)
}
}
.padding()
.navigationTitle("Notes")
}
}
}
|
Recommended Learning Order
- Swift basics
- Swift optionals and closures
- Struct, class, protocol, extension
- SwiftUI basics
- SwiftUI state management
- Navigation and lists
- MVVM architecture
- Networking
- Local storage
- Async/await and concurrency
- UIKit basics
- Debugging
- Testing
- Security
- App Store release
- Advanced frameworks
- Real project development