Example App for playing around with

Overview

BookStore

πŸ‘‰ ν•œκΈ€ 버전

See new releases and search for programming books from IT Bookstore API

This is a sample app to practice using Result type, stubbing network request for unit tests, separating functionalities into frameworks, and writing Swift documentation.

How to run

> cd BookStore
> open BookStore.xcodeproj

Run!

Contents

App Features

What's New

A simple UITableView with cells and modal presentation for a detailed page.

Search

  1. As a user types in the keyword, the search text is "debounced" for a fraction of second for better performance and user experience. See Debouncer.

  2. Search results are paginated and provides infinite scroll.

Result type in Swift 5

Out of the box, you have to switch on the Result instance to access the underlying success instance or the error instance.

switch result {
case .success(let response):
  //do something with the response
case .failure(let error):
  //handle error
}

However, I think switch statements are too wordy. I added success and catch method to Result type. So it can be chained like this.

searchResult.success { response in
  //do something with the response
}.catch { error in
  //handle error
}

Even cleaner, like this.

result.success(handleSuccess)
      .catch(handleError)
      
func handleSuccess(_ result: SearchResult) { ... }
func handleError(_ error: Error) { ... }

Stubbing Network Requests for Unit Tests

Generally, it is not a good idea to rely on the actual network requests for unit tests because it adds too much dependency on tests. One way to stub networking is to subclass URLProtocol.

1. Subclass URLProtocol

See MockURLProtocol

2. Configure URLSession with your mock URLProtocol

let config = URLSessionConfiguration.ephemeral
config.protocolClasses = [MockURLProtocol.self]

//Use this URLSession instance to make requests.
let session = URLSession(configuration: config) 

4. Use the configured URLSession instance just as you would.

session.dataTask(with: urlRequest) { (data, response, error) in
  //Stubbed response
}.resume()

UI Testing with Stubbed Network Data

The above method(as well as the famous OHHTTPStubs) doesn't work for UI testing because the test bundle and the app bundle (XCUIApplication) are loaded in separate processes. By using Swifter, you can run a local http server on the simulator.

First, change the API endpoints during UI testing with launchArguments in your hosting app.

//In XCTestCase,
override func setUp() {
  app = XCUIApplication()
  app.launchArguments = ["-uitesting"]
}

//In AppDelegate's application(_:didFinishLaunchingWithOptions:)
if ProcessInfo.processInfo.arguments.contains("-uitesting") {
  BookStoreConfiguration.shared.setBaseURL(URL(string: "http://localhost:8080")!)
}

Then stub the network and test the UI with it.

0) XCTAssert(app.staticTexts["9781788476249"].exists) XCTAssert(app.staticTexts["$44.99"].exists) } } ">
let server = HttpServer()

func testNewBooksNormal() {
  do {
    let path = try TestUtil.path(for: normalResponseJSONFilename, in: type(of: self))
    server[newBooksPath] = shareFile(path)
    try server.start()
    app.launch()
  } catch {
    XCTAssert(false, "Swifter Server failed to start.")
  }
        
  XCTContext.runActivity(named: "Test Successful TableView Screen") { _ in
    XCTAssert(app.tables[tableViewIdentifier].waitForExistence(timeout: 3))
    XCTAssert(app.tables[tableViewIdentifier].cells.count > 0)
    XCTAssert(app.staticTexts["9781788476249"].exists)
    XCTAssert(app.staticTexts["$44.99"].exists)
  }
}

Using Frameworks for independent functionalities

Separating your app's functions into targets has several advantages. It forces you to care about dependencies, and it is good for unit tests since features are sandboxed. However, it may slow down the app launch (by little) due to framework loading.

BookStoreKit is responsible for fetching and searching books data from IT Bookstore API.

Networking is a wrapper around URLSession for making HTTP requests and parsing response.

Writing a documentation comment

Swift's API Design Guidelines suggest you write a documentation comment for every declaration. Writing one can have an impact on the design.

1. Write

Reference this document for markup formatting.

2. Check out the result

In Xcode's autocompletion

and Show Quick Help (option + click)

Getting Rid of IUOs

IMHO Implictly unwrapped optional is a potential threat to code safety and should be avoided as much as possible if not altogether. An example of two methods to get rid of them from where they are commonly used.

Make IBOutlets Optional

IBOutlets are IUOs by Apple's default. However, you can change that to Optional types. You may worry that making IBOutlets Optionals may cause too many if lets or guards, but that concern may just be overrated. IBOutlets are mostly used to set values on them, so optional chaining is sufficient. In just few cases where unwrapping is added, I will embrace them for additional safety of my code.

Using lazy instantiation

For the properties of UIViewController subclass, IUO can be useful but it's still dangerous. Instead, I use unspecified. It generates a crash upon class/struct usage so it can be spotted fast during development, and most importantly no more IUOs.

//Inside a viewcontroller
lazy var bookStore: BookStoreService = unspecified()
You might also like...
An example project of using the new Character Controller component in RealityKit 2.0
An example project of using the new Character Controller component in RealityKit 2.0

CharacterController in RealityKit 2.0 An example project of using the new Character Controller component in RealityKit 2.0. Demo Tweet Usage Install a

This is example project for my presentation in iOSDC JAPAN 2021

Swift PM Project Example This is example project for my presentation in iOSDC JAPAN 2021. Package.swift based project management Multi Modules Multi P

Example Xcode swift iOS project for Core Data + iCloud syncing
Example Xcode swift iOS project for Core Data + iCloud syncing

iCloudCoreDataStarter Hello, I'm Chad. For the last several months I have been working on Sticker Doodle, an app you should go download right now! In

An example of adding a faux notch using AppKit + SwiftUI
An example of adding a faux notch using AppKit + SwiftUI

faux-notch An example of adding a faux notch using AppKit + SwiftUI What is this? It's a bare-bones example that renders a fake MacBook notch in macOS

A repository of example plugins for Delta Client

Example Plugins for Delta Client This repository contains a few example plugins to help developers get a practical understanding of how to use the plu

CustomPod Example Axon With Swift

CustomPod_Example_Axon Example To run the example project, clone the repo, and run pod install from the Example directory first. Requirements Installa

Here there is a simple example using watchOS and SwiftUI
Here there is a simple example using watchOS and SwiftUI

A Simple Demonstration Project using WatchOS + SwiftUI Description This project is a simple demonstration about how to create a WatchOS App using Swif

Todolist-swiftui - An example of using SwiftUI with CoreData

todolist-swiftui An example of using SwiftUI with CoreData Installation Install

SwiftUI + Combine + MVVM - Book search example
SwiftUI + Combine + MVVM - Book search example

CombineBookSearch SwiftUI + Combine + MVVM Example project of SwiftUI and Combine using MVVM architecture pattern.

Owner
Danny Gilbert
"Any fool can write code that a computer can understand. Good programmers write code that humans can understand."​ - Martin Fowler
Danny Gilbert
ZEGOCLOUD's easy example is a simple wrapper around our RTC product.

ZEGOCLOUD's easy example is a simple wrapper around our RTC product. You can refer to the sample code for quick integration.

null 1 Dec 14, 2022
Example on how to print a NSTableView from your app but then also add text to the print-out.

NSTableView Printing Test This is a demo project so you can check out how printing a table could work. The goal here is to show tabular data on screen

Clean Cocoa 3 Mar 29, 2022
An example app with using ShazamKit

ShazamKitExample An example app with using ShazamKit. Check out a live demo on Twitter. Related Resources Introducing ShazamKit WWDC21 β€” Explore Shaza

Artem Novichkov 10 May 25, 2022
Example project guide you schedules multiple thread for network requests in RxSwift, which is optimize your app's performance better.

RxSwift-Multi-Threading-Example Example project guide you schedules multiple thread for network requests in RxSwift, which is optimize your app's perf

Huy Trinh Duc 6 Nov 4, 2022
MVVM example app with RxSwift & RxDataSources & Dependency Injection & UnitTests

Hi there, This is MVVM example app with RxSwift & RxDataSources & Dependency Injection & UnitTests and more ?? MVVM with RxSwift Example Features: Rea

Ali Fayed 9 Aug 30, 2022
SwiftUI Todo app example using a React/Redux monolithic state store with flux like dispatch/reduce actions

SwiftUI-Todo-Redux SwiftUI Todo Redux app example using a React/Redux monolithic state store with flux like dispatch/reduce actions Background SwiftUI

moflo 12 Nov 29, 2022
SwiftUI Navigation example app

SwiftUINavigationExample SwiftUI Navigation example app. Navigation is managed by a single class called NavSwitches. This contains all the booleans th

Luke Smith 4 Feb 18, 2022
Example app source code developed by swift language from apple

AboutMe Example app source code developed by swift language from apple. Display data from a central source in multiple views. Welcome to the About Me

yuezht 0 Mar 29, 2022
Advanced Catalyst Example with sidebar, list view, SwiftUI detail view, toolbar & AppKit bundle

Advanced Catalyst Example This is an example of a Catalyst app using a three-column layout, with a primary toolbar. It includes topics such as: Drag &

Steven Troughton-Smith 219 Dec 8, 2022
Example for RxFeedback

RxFeedback Sample This is a repository for the RxFeedback code sample. Running Install bazel (This project is tested with Bazel 4.0.0) bazel run //App

Snorlax 4 Oct 8, 2021