Summary of iOSDC Japan 2021

Kent Strong (Kento Yamazaki)
11 min readSep 18, 2021

iOSDC Japan is the biggest conference of iOS developers in Japan. I'm going to introduce some of the sessions and useful insights developing iOS apps.

You can check out the timetable of the event here.

The Art of Large-Scale Refactoring

What to refactor

They decided to refactor the code of routing rogic, which means screen routing in iOS apps, because they were becoming fat and difficult to understand. At least at the beginning, they limited the code to refractor only to the routing logics, because refactoring so many areas at once makes a mess.

Who to refactor

They assigned some of the team members only to refactor codes, without writing products. It takes a lot of time and cost to refactor codes to make it effective, so they decided use certain amount of exclusive manpower.

Because they were originally team member who wrote the product code, they already know the product codes have what kind of structure and what kind of problems. This knowledge help them easily and efficiently refactor codes. In a quite large scale product like them, it is important to pay exclusive costs or manpower to refactor, Which does not necessarily apply to small scale products, I guess.

Also, in refactoring, if you are going to apply a new architecture to the program, the refactor member should know how to write that.

Where to start refactoring from

They said you should start to refactor from where you have some problems in your product codes, like routing logic which growing so fat.

A part of codes which currently is not being developed is also a good point to start to refactor.

But if you are tweaking the same area as a business project which is being developed, take advantage of large-scale functional improvements. That way you can secure time to test the code you refactored. To do that you need to know when is the business project is going to be released. Schedule when to start to refactor so you can meet the time of release.

Automation of routine tasks

They used the tool called “danger” to automatically detect the code which is not used at all. That way they were able to keep codes clean.

I tried using it, and it looks like just working on GitHub. I'm sure you can make use of other linting tools for other continuous integration platforms like Gitlab.

They also use the tool called “chxcode” to automatically change the Xcode versions and open them for different branches. It is hassle to open different versions of Xcode manually. I also tried using it, it was easy to use because you just need to create a file called “.xcode-version”, which describes what version of Xcodes the product need to use.

Also they use the bot to test and create merge request of the development or fix of the product code into the refactoring branch. The bot can do it automatically during the night. Unless there are any conflict, you just need to click merge button in the morning.

Lastly they made use of the tool called RIBsCodeGen to create a boiler plate for an architecture RIBs, which is an architecture proven to scale to hundreds of engineers working on the same codebase. This tool saved a lot of time to create a lot of template files manually.

The story of how we released a live streaming feature using agora in a month and a half

They implemented an app, where users can broadcast live streaming and give a gift to performers, in a month and a half. They made use of Agora, which is also used by Clubhouse app.

The story of migrating from SQLite to Firestore for an application used by 5 million people in its 6th year of operation

English study application called Mikan, migrated it’s data from local SQLite DB to online cloud-based no SQL data storage “Firestore”.

Originally, they only stored users data on local SQLite storage.

Firstly, they started to write uses new data both into local SQLite and into the online Firestore at the same, to prepare future complete migration. At this point they also recorded the date when they started double write for next phase.

Secondly, they uploaded whole data, which are around before they start to double write, onto the GCS or Google Cloud Strage. They used date which they recorded on the first phase to judge which data are needed to upload.

Finally, they started to write data only to the cloud Firestore. On the one hand SQLite is that relational database, on the other hand Firestore is no SQL so-called KVS or key value system. They said they had a hard time changing the logic writing data, adjusting from RDB system to KVS system.

What We learned after running an app using SwiftUI for a year

They adopted MVVM architecture with SwiftUI.

Parent views that each represent one screen on app have a multiple child views. On the other hand view model also has multiple child view models that conform to “@ObservableObject” attribute. They are counterparts of child views. After a parent view received a view model, it deals out child view models to child views. That way you can handle large complex structure.

For the basic usage of the observable object, see here.

After running the app, they noticed a view that is set to a navigation link as a destination is immediately initialized, and many other objects connected with the view is also initialized immediately. This is waste of memory, so they used “LazyView” to delay the initialization of the destination views and other related objects. It looks like that lazy view use “@autoclosure” attribute on a closure that is passed to the lazy view. Inside of the closure the content view is initialized. The lazy view uses the closure when some other object first access to its body property, so the initialization of content view is not performed until this point.

A Swift Stack Overflow

When you interact with C language from swift code, you need to take care not to cause stack overflow.

You can wrap large C struct so that it won't cause stack overflow.

Also, you better prefer to use while loop rather than recursive function call to avoid stack overflow a.k.a. EXC bad access.

You can try to debug stack overflow with the author’s repository in Github.

PickGo for Partner Replacing Native Apps with Flutter

Because their native iOS and android apps were creative mainly from WebViews, it is difficult for them to improve functionalities fast. So they decided to replace it with Flutter.

They adopt the change notifier provider, which is the basic state management framework in Flutter. This framework makes it possible to manage a bit complicated state. So it’s better than just passing closures to child widgets regarding state management.

They use retrofit as a API client and freezed for code generation.

How to release apps faster with SwiftUI

When sending event trucking to Firebase Analytics, they created a custom view modifier that conforms to viewModifier protocol. Inside of onAppear modifer in the body property they perform sending event to fire base analytics.

In iOS 13, 14 and even 15, is it impossible to add an accessory view on the keyboards with swiftUI. So they used UIKit instead if they need to set text fields on the screen.

What I learned from my first foray into iOS app development and the challenge of Unity as a Library

https://fortee.jp/iosdc-japan-2021/proposal/a16b86e6-8e91-4675-9c8f-e7f38c609b2f

They use unity as a library that is a combination of the native Swift language and the unity library, to realize the combination of 3-D graphic of unity and basic UI of iOS.

How to implement a usable design system for OS and Android

They introduced design system that salesforce originally advocated. It is based on the concept “the single source of truth” and can apply the same design to iOS and android.

Learn Package Manager by looking back

Three package managers on iOS development, that are Cocoapods, Carthage and swift package manager(SPM).

Cocoapods gathers all libraries needed, automatically combine them with your product project, and build them at product build. It doesn't build libraries when gathering them. Instead, it does so when product builds. So it will take more time to build products. It might cause problems especially when the product is so large. Also all the libraries distributed by Cocoapods, need to submit PodSpec file to the Cocoapods repository in Github. So you could say Cocoapods is a centralized system of gathering and distributing libraries.

On the other hand Carthage builds all the libraries it gathered immediately. So you don’t have to build it on your product build.Product can build faster. But it means gathering libraries takes more time. Also Carthage doesn’t integrate gathered libraries into your project so you need to do it manually. And Carthage doesn’t manage any information of libraries itself like Cocoapods does, so you could say Carthage is a decentralized system of distributing libraries.

Swift package manager is similar to Carthage in terms of its system. It builds gathered libraries in advance. The swift package manager’s characteristic is that it’s an official tool of Xcode. So it automatically integrates gathered library into your product codes. It’s easy to use with Xcode GUI. Recently SPM is hugely improved so it’s a good time to try using it. Fortunately, you can use swift package manager and other package managers at the same time.

Best practice of end of a subscription service

https://speakerdeck.com/tbl_ota/toaruapurifalsesabisuzhong-liao-wojian-jie-keru-sabusukuripusiyonxing-apurifalsesabisuzhong-liao-besutopurakuteisu

  1. Tell users when subscription service ends. It’s good to use multiple way to inform users like with push notification, the product’s website and some notification in your app.
  2. Make your subscription service unavailable from App Store.
  3. Wait until all users’ subscriptions end because of the expiration.
  4. Remove your app from App Store.

Building an Identity Verification Flow for a Seamless Experience — An Example of eKYC Development for a housekeeping app Plica B/43

https://speakerdeck.com/nakamuuu/iosdc-japan-2021

eKYC is a way to verify users’ identity through the internet, without using telephones, mails and reception desks.

You can use external high-quality SDK of eKYC like this.

But on this Plica BS/43 app, they implemented eKYC totally on their own to realize seamless identity verification flow.

Creating automatic code generation tool with Source Editor Extension and SwiftSyntax

https://speakerdeck.com/kazuhiro4949/source-editor-extensionto-swiftsyntaxdekodozi-dong-sheng-cheng-turu-wozuo-ru

He created an automatic code generation tools, DI Helper for Swift and Access Level Changer for Xcode.

The former can automatically generate protocols from class implementation, and even can create mocks from the protocols.

The latter can change internal accessibility level into public level automatically. It can use when you create framework.

They make use of source editor extension and swift-syntax.

Automatic code generation tools with source editor extension and swift-syntax should be third alternative to generate codes apart from Xcode template and Run Scripts.

Your first hardware support

https://speakerdeck.com/ykkc/chu-metefalsehadoueadui-ying

They created an app called STORES Register that is used in checkout counters in shops. This app can connect with various peripherals like cash drawers, receipt printers and barcode readers.

This app uses Bluetooth Low Energy a.k.a. BLE, which you can implement with Core Bluetooth Framework, and Bluetooth classic, Which you can implement with External Accessory Framework.

Split Japanese Sentences

https://speakerdeck.com/trickart/split-japanese-sentence-for-uilabel-and-swiftui-text

In the case of English, by specifying byWordWrapping in NSLineBreakMode, you can make the line break just at the end of the word on the UILabel. But in Japanese it can’t. So he created a tool called muscat to do it. This tool uses MeCab, which is a C++ library for morphological analysis.

Cookpad app multi-module structure

https://speakerdeck.com/giginet/da-gui-mo-naapurifalsemarutimoziyurugou-cheng-falseshi-jian?slide=58

Tools

for creating multi module(multi target)

for code generation, like mocks, protocols…

Structure of Cookpad app multi-module devision

Feature: Dynamic library. It contains group of scenes that have the same domain layer in common.

Some Feature -> via Environment -> Core Module(API Client, Logger, etc…)

Some Feature -> (passing Descriptor) -> via Environment.resolve() -> Another Feature(XXViewController…)

Some Feature -> Another Feature ❌

Testing

Pass stub environment to data store. Register test response corresponding your request to stub environment. Data Store returns test response registered in stub environment.

SandBox app target

Have one Feature only, does not have other Feature modules. See other modules stub by resolver and stub environment.

Sandbox needs to prepare a lot of dummy codes, so all sandboxes look at common module SandboxCore.

Other articles

https://github.com/aomathwift/SandboxKit

https://techlife.cookpad.com/entry/2021/06/16/110000

https://speakerdeck.com/masamichi/merupeifalsesukerabiriteiwozhi-erumarutimoziyurukai-fa?slide=16

https://mercari.connpass.com/event/213078/

Implemented automatic screenshot generation for App Store with Arabic support and SwiftUI

https://fortee.jp/iosdc-japan-2021/proposal/3acc5289-434e-4cdc-a3b8-05e7aae26738

You can do automatic code generation for App Store with snapshot and frameit of Fastlane. They added Arabic language support on their own.

All about accessibility implemented in note’s iOS app

https://fortee.jp/iosdc-japan-2021/proposal/1388d639-901b-4e46-bba4-be866aba7130

They implemented VoiceOver functionality in iOS notes app for the blind people. They introduced bugs they encountered in development.

The Challenge of App Size Optimization

https://fortee.jp/iosdc-japan-2021/proposal/d94af9ca-e450-44cf-b419-89e45772066e

If your app size is so large, users tend to uninstall your app. So it’s important to reduce the size of your app.

  1. Turn on App Thinning when you archive release app. This option enables the app only include resources that needed for specific device.
  2. You can see if there are unnecessary files in an ipa file by renaming it with zip extension and open the package content. Also, you can checkout the files sizes in a binary file with google/bloaty. See usage here: https://fuchsia.googlesource.com/third_party/bloaty/+/96f93a01085fba17805425d74deec83f2d927d4a/README.md

For other measures, see above material.

The Story of How We Answered App Privacy Questions and Supported ATT

https://speakerdeck.com/fromatom/iosdc-japan-2021

Starting with iOS 14.5, iPadOS 14.5, and tvOS 14.5, you’ll need to receive the user’s permission through the AppTrackingTransparency framework to track them or access their device’s advertising identifier. Tracking refers to the act of linking user or device data collected from your app with user or device data collected from other companies’ apps, websites, or offline properties for targeted advertising or advertising measurement purposes. Tracking also refers to sharing user or device data with data brokers.

https://developer.apple.com/app-store/user-privacy-and-data-use/

  • Your app collects your users’ IDFA
  • Your app collects other users’ private information for tracking, which means to combine it with other information gathered through other company’s system

In these case your app needs to use ATT framework to get a permission from the user. In this session, Pixiv company does collect uses private information and uses it on it’s own advertisement, but does not combine it with information gathered from other companie’s system. So they do not need to use ATT framework to get a permission from users.

Recommendations for run-time debugging

He created a high-quality debug menu library that you can download through cocoapods or SPM.

Also, he recommends to use RPScreenRecorder to let testers create a clip and share it with the development team. In this way the development team can get clear feedback about what happened on the app. You can write codes like below.

import ReplayKit

/// starts monitoring right after app launch

func launched() async throws {

try await RPScreenRecorder.shared().startClipBuffering()

}

func onTapClipShareButton() throws {

let url: URL = URL(string: “”)!

try await RPScreenRecorder.shared().exportClip(to: url, duration: 5)

try await RPScreenRecorder.shared().stopClipBuffering()

shareVideo(url)

}

Don’t be afraid of apps getting killed in the background! All about the Restore function that restores the app state

  • Not using SceneDelegate: You can restore app’s screen and state with RestorationID of Storyboard and NSCoder.
  • Using SceneDelegate: You can restore app’s screen and state with NSUserActivity.

Official documents:

Restoring your app’s state

Restoring Your App’s State with SwiftUI

Hello, Swift Concurrency world

Easily and correctly format any information into a String

He introduces all formatters available in swift language:

Date, time, quantites of time, %, currency, exponential notation, byte size (MB, GB…), person’s name, acceleration, angle, area, volume, mass, concentration, period, electricity, energy, frequency, fuel consumption, illumination, length, pressure, speed, temperature…

--

--