Monday, March 4, 2024
Swift Rule Engine using Javascript for your iOS/MacOS application
Tuesday, February 27, 2024
Swift async/await - Sample API module with Unit test
Create Swift Package
In Xcode Menu, choose New -> Package from file menu.platforms: [
.iOS(.v13),
.macOS(.v12)
]
To consume the session tasks, we need url requests, for example assume our app have a feature to fetch the contacts from server. Also modify the getMyContacts() func.public func getMyContacts() async throws -> [Contact] {
let contactRequest = ContactEndPoint.myContacts.url(baseURL: baseURL)
let (data, httpResponse) = try await client.performRequest(contactRequest)
return try ContactDataMapper.map(data, from: httpResponse)
}
Create New Unit Test Case
Create protocol HTTPURLSession
And in the HttpClient class, change the type of session variable as HTTPURLSession.public protocol HTTPURLSession {
func data(for request: URLRequest) async throws -> (data: Data, response: HTTPURLResponse)
}
func test_init_doesNotExecuteURLRequest() async {
let (_, session) = makeSUT()
let executedUrls = session.executedURLs
XCTAssertTrue(executedUrls.isEmpty)
}
func test_deliverConnectivityErrorOnClientError() async throws {
let (sut, _) = makeSUT()
do {
_ = try await sut.getMyContacts()
} catch let error {
XCTAssertEqual((error as? APIError), APIError.connectivity)
return
}
XCTFail()
}
func test_deliverErrorOnInvalidJSONWith200Status() async throws {
let url = URL(string: "https://aurl.com")!
let (sut, session) = makeSUT(url: url)
let myContactURL = ContactEndPoint.myContacts.url(baseURL: url).url!
let invalidJSON = """
[
{"contactsssss_ID" : 2 }
]
"""
session.setResponse((invalidJSON.data(using: .utf8)!, responseWithStatusCode(200, url: myContactURL)), for: myContactURL)
do {
_ = try await sut.getMyContacts()
} catch let error {
XCTAssertEqual((error as? APIError), APIError.invalidData)
return
}
XCTFail()
}
func test_load_DeliverErroFor400Status() async throws {
let url = URL(string: "https://aurl.com")!
let (sut, session) = makeSUT(url: url)
let myContactURL = ContactEndPoint.myContacts.url(baseURL: url).url!
session.setResponse(("".data(using: .utf8)!, responseWithStatusCode(400, url: url)), for: myContactURL)
do {
_ = try await sut.getMyContacts()
} catch let error {
XCTAssertEqual((error as? APIError), APIError.serverDefined("400"))
return
}
XCTFail()
}
func test_load_deliversSuccessWith200HTTPResponseWithJSONItems() async throws {
let url = URL(string: "https://aurl.com")!
let (sut, session) = makeSUT(url: url)
let validJSON = """
[
{"contact_ID" : 2 }
]
"""
let myContactURL = ContactEndPoint.myContacts.url(baseURL: url).url!
session.setResponse((validJSON.data(using: .utf8)!, responseWithStatusCode(200, url: url)), for: myContactURL)
do {
let contacts = try await sut.getMyContacts()
XCTAssertEqual(contacts.count, 1)
} catch {
XCTFail()
}
}
@MainActor func test_load_DeliverConnectivityErrorIfTaskIsCancelled() async throws {
let url = URL(string: "https://aurl.com")!
let (sut, session) = makeSUT(url: url)
let dataResponse = """
[
{"contact_ID" : 2 }
]
"""
let myContactURL = ContactEndPoint.myContacts.url(baseURL: url).url!
session.setResponse((dataResponse.data(using: .utf8)!, responseWithStatusCode(200, url: url)), for: myContactURL)
let exp = expectation(description: "Wait for load completion")
let task = Task {
do {
let contacts = try await sut.getMyContacts()
exp.fulfill()
XCTAssertEqual(contacts.count, 0)
} catch let error {
exp.fulfill()
XCTAssertEqual((error as? APIError), APIError.connectivity)
}
}
task.cancel()
await fulfillment(of: [exp])
}
Thursday, January 23, 2020
Swift enum - make Encodable
struct Request: Encodable {
var status: MacStatus
var macName: String
}
enum MacStatus {
case running
case notRunning
}
Now we want to make the enum MacStatus as encodable. So we can use singleValueContainer
extension MacStatus: Encodable {
var josnKey: String {
switch self {
case . running:
return "Running"
case . notRunning:
return "Not Running"
}
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(josnKey)
}
}
Another way is below:
enum MacStatus: String, Encodable {
case running
case notRunning
var rawValue {
switch self {
case . running:
return "Running"
case . notRunning:
return "Not Running"
}
}
}
Sunday, March 18, 2018
Swift Code Review
- to keep good coding practice
- to maintain the code looks similar
- to reduce bugs
- to improve performance
One of the best way to follow good swift styles is using Swift Lint
Here are some other tips for code review:
1.
Reduce the use of red text. We have to keep an eye on the text with red colour ( I am mentioning the Xcode default format).
The only text in red colour should be the key in Localizable.strings file or some print statements.
2.
Reduce the usage of 'self.'
The only place 'self.' can exist should the init() or constructors of a class.
If we forced to use self in any closures, then apply [weak self] for the arguments and add a guard statement. Check below example:
3. Reduce the usage of integer or string constants.
group it using enum if possible.
Wednesday, February 21, 2018
iOS - Fix Massive View Controller using MVP+VM Architecture
1. Router
- The Router class will capable to handle all navigations such as segue or custom.
- Capable to construct the view controller
- Capable to pass data to other view controllers
A sample Router class is shown below:

So we will always call addContracts() function when ever construct a view controller
2. SBControl
This class will keep all storyboard controls, and its makeups such as setting font, colours and localised texts and animations etc..
I am not repeating how to do this, Its well explained here see the section "Solution 2: Presentation Controls"
So
The VC (View Controller) can have minimum one IBOutlet reference to the Object control.
3. Presenter - implements UIEvents protocol
Responsible to handle user actions from View Controller. This is just a dispatcher. Handle a little business logics. Presenter will ask to viewmodel to perform the data manipulations and will return the result to the view controller using the DisplayUI protocol which is implemented by View Controller.
Presenter will give the navigation task to the router
Presenter will give the display task to the view controller
Presenter will give the network operations to the service class
4. Service - optional
Responsible to all network operations. Presenter will hold a protocol reference which is implemented by Service class
5. ViewModel
There will be separate view models for each view. It will be responsible to handle business logic as well as the presentation logic. Both will be grouped using protocols.
6. ViewController
Responsible to the VC life cycle. Inform all UI actions to the Presenter. ViewController implements a DisplayUI protocol.
7. UIController (optional)
Handle the tableview/collection/text view delegates here to reduce the code in View Controller and also to distribute the functionalities.

Following is the template to create the files.
https://github.com/davidpaul0880/Swift-Template
Can post more when get more free time..
But post comment if you have any questions, or need clarifications.

