The Repository pattern helps keep your app organized by separating data access from the rest of your code. It acts like a middleman between your app and data sources.
Repository pattern in iOS Swift
protocol Repository {
associatedtype Item
func fetchAll() -> [Item]
func add(_ item: Item)
func remove(_ item: Item)
}This is a simple protocol defining what a repository should do.
Use associatedtype to make it work with any data type.
struct User {
let id: Int
let name: String
}
class UserRepository: Repository {
typealias Item = User
private var users = [User]()
func fetchAll() -> [User] {
return users
}
func add(_ item: User) {
users.append(item)
}
func remove(_ item: User) {
users.removeAll { $0.id == item.id }
}
}class RemoteUserRepository: Repository { typealias Item = User func fetchAll() -> [User] { // Imagine fetching from a server here return [User(id: 1, name: "Alice")] } func add(_ item: User) { // Send user to server } func remove(_ item: User) { // Remove user from server } }
This program creates a user repository, adds two users, then removes one. It prints the list of users before and after removal.
import Foundation struct User: Equatable { let id: Int let name: String } protocol Repository { associatedtype Item func fetchAll() -> [Item] func add(_ item: Item) func remove(_ item: Item) } class UserRepository: Repository { typealias Item = User private var users = [User]() func fetchAll() -> [User] { return users } func add(_ item: User) { users.append(item) } func remove(_ item: User) { users.removeAll { $0.id == item.id } } } // Using the repository let repo = UserRepository() repo.add(User(id: 1, name: "Alice")) repo.add(User(id: 2, name: "Bob")) print("Users after adding:", repo.fetchAll()) repo.remove(User(id: 1, name: "Alice")) print("Users after removing Alice:", repo.fetchAll())
The Repository pattern helps you swap data sources easily without changing your app logic.
Keep repository methods simple and focused on data operations.
Use protocols to define repository behavior for flexibility and testing.
The Repository pattern separates data access from app logic.
It makes your code cleaner and easier to maintain.
You can switch data sources without changing the rest of your app.
Practice
What is the main purpose of the Repository pattern in iOS Swift development?
Solution
Step 1: Understand the role of Repository pattern
The Repository pattern is designed to isolate data access logic from business logic in an app.Step 2: Identify the correct purpose
Separating data access makes the app easier to maintain and test, which matches To separate data access logic from the rest of the app.Final Answer:
To separate data access logic from the rest of the app -> Option AQuick Check:
Repository pattern = separate data access [OK]
- Confusing Repository with UI or navigation roles
- Thinking Repository manages animations
- Assuming Repository stores UI layout
Which of the following is the correct way to declare a repository protocol in Swift?
?Solution
Step 1: Identify correct Swift syntax for protocols
Protocols in Swift are declared with the keywordprotocolfollowed by method signatures without bodies.Step 2: Match the correct declaration
protocol UserRepository { func fetchUsers() -> [User] } correctly declares a protocol with a method signature. Other options use class, struct, or enum which are not protocols.Final Answer:
protocol UserRepository { func fetchUsers() -> [User] } -> Option DQuick Check:
Protocol declaration usesprotocolkeyword [OK]
- Using class or struct instead of protocol for interface
- Adding method bodies inside protocol
- Using enum incorrectly for repository
Given the following code snippet, what will be printed?
protocol UserRepository {
func fetchUsers() -> [String]
}
class MockUserRepository: UserRepository {
func fetchUsers() -> [String] {
return ["Alice", "Bob"]
}
}
let repo: UserRepository = MockUserRepository()
print(repo.fetchUsers())Solution
Step 1: Understand protocol conformance and method implementation
The classMockUserRepositoryconforms toUserRepositoryand implementsfetchUsers()returning ["Alice", "Bob"].Step 2: Analyze the print statement
The variablerepois typed asUserRepositorybut holds an instance ofMockUserRepository. CallingfetchUsers()returns ["Alice", "Bob"], which is printed.Final Answer:
["Alice", "Bob"] -> Option BQuick Check:
Protocol method returns mock data [OK]
- Expecting empty array instead of returned data
- Thinking protocol variable can't call methods
- Assuming compilation error due to protocol
Identify the error in this repository implementation:
protocol UserRepository {
func fetchUsers() -> [String]
}
class UserRepo: UserRepository {
func fetchUsers() {
return ["Alice", "Bob"]
}
}Solution
Step 1: Compare protocol and class method signatures
The protocol methodfetchUsers()returns[String]. The class method lacks the return type in its signature.Step 2: Identify the mismatch causing error
Because the class method signature does not match the protocol, it causes a compilation error. The method must declare the return type.Final Answer:
Missing return type in method signature -> Option CQuick Check:
Method signatures must match protocol [OK]
- Forgetting to add return type in implementation
- Assuming method name mismatch
- Thinking protocol conformance is automatic
You want to switch your data source from a local database to a remote API without changing your app's business logic. How does the Repository pattern help you achieve this?
Solution
Step 1: Understand the role of repository interface
The Repository pattern uses an interface (protocol) to abstract data access methods.Step 2: Implement separate classes for each data source
You create one class for local database access and another for remote API, both conforming to the same interface. This allows switching without changing business logic.Final Answer:
By defining a repository interface and implementing separate classes for each data source -> Option AQuick Check:
Interface + multiple implementations = easy data source switch [OK]
- Mixing data fetching code in UI layer
- Using global variables for data access
- Combining local and remote logic in one class
Ready to prove it?
Pass the test and this pattern moves unknown
