A better way to update UICollectionView data in Swift with diff framework
Issue #1010
A Better Way to Update UICollectionView Data in Swift with Diff Framework
Familiar Friends
It’s hard …
Issue #1010
It’s hard …
Issue #1009
SwiftUI’s Observation framework makes reactive UI updates effortless—when a property changes, views that depend on it automatically refresh. But what happens when your data lives in UserDefaults? You might want subscription status, …
Issue #1007
Testing in Swift has always required inheriting from XCTestCase and prefixing every method with test. Sound familiar? With Swift 6, Apple introduced Swift Testing — a framework that feels native to modern Swift …
Issue #997
An interesting feature in iOS 26 is the ability to create morph “Liquid Glass” effects, where views with the .glassEffect() modifier can fluidly morph into one another. This is achieved using GlassEffectContainer and the …
Issue #996
When creating widgets for iOS, especially those that need user input to be useful, one common challenge is guiding the user to configure them. Before iOS 18, a user would add a widget, but then would have to know to long-press it and …
Issue #995
With iOS 18, SwiftUI introduces matchedTransitionSource and navigationtransition as a powerful new way to create zoom animations between views. This allows you to smoothly transition from a small view to a larger, more detailed view, …
Issue #994
With iOS 18, Apple introduced a powerful new tool for creating beautiful, dynamic backgrounds: MeshGradient. Forget simple two-color gradients; mesh gradients let you blend a whole grid of colors together smoothly, creating stunning, …
Issue #993
Before iOS 17, if you wanted to animate a number changing, SwiftUI would just fade the old number out and fade the new one in. It worked, but it wasn’t very exciting.
Here’s how that looked:
struct OldCounterView: View {
@ …Issue #992
In the past, making your screen update when data changed in UIKit meant writing extra code, either with didSet, Combine or some other callbacks. Now, it’s automatic.
With the latest iOS 26 updates, UIKit can automatically watch your …
Issue #991
When building apps in SwiftUI or React, we often need to store values that change — like a counter, user input, or a list of items.
To do this:
useState.@State and @StateObject.But here’s something cool: …
Issue #990
In many popular apps like LinkedIn, Reddit, we can tap again on a bar bar item to scroll to top. Although this behavior is not built in by iOS, we can implement that very easily.
The idea is to keep track of previous selection so we can …
Issue #983
In iOS 18, we can make Control Widget in Widget extension
import WidgetKit
import SwiftUI
@available(iOS 18.0, *)
struct BookControlWidget: ControlWidget {
var body: some ControlWidgetConfiguration {
StaticControlConfiguration …Issue #973
Before iOS 11, we used to use CIDetector and CIDetectorTypeQRCode to detect QR code
An image processor that identifies notable features, such as faces and barcodes, in a still image or video.
A detector …
Issue #972
We want to have a swifty UserDefaults API that works with subscript and in a type safe manner.
extension Defaults.Keys {
static let string = Defaults.Key("string", default: "0")
}
XCTAssertEqual(defaults[.string], …Issue #963
In the world of Swift programming, we often come across situations where we need to work with string literals that contain special characters. These characters can include new lines, tabs, backslashes, and quotes — all of which need to be …
Issue #960
Also written on Fritz
Math might be scary, but it’s an essential part of everyday life. Wouldn’t it be cool if we could build an app, point our phone’s camera at an expression, and let the app compute the result? Whenever I’ve needed to …
Issue #957
Define console object and set log function to point to our Swift function
import JavaScriptCore
extension JSContext {
func injectConsoleLog() {
evaluateScript(
"""
var console = {}; …Issue #956
import Foundation
import SwiftUI
import AppKit
struct AttributedTextView: NSViewRepresentable {
@Binding var attributedText: NSAttributedString
var isEditable: Bool = true
final class Coordinator: NSObject { …Issue #955
Besides WWDC videos & documentation, Apple also has interactive tutorials and books. Below are some of my favorites learning resources
Tutorials
Issue #948
iOS 17 has a new Stand by mode so SwiftUI introduces containerBackground for the system to decide when to draw background. It also automatically applies margin to widget so we may need to disable that
To update existing widgets, we can …
Issue #938
To let app and extension to talk to the same database, we need to use AppGroup. Here is how to use replacePersistentStore
Replaces one persistent store with another
actor DatabaseMigrator {
@AppStorage( …Issue #937
First, you need to enable iCloud Documents capability. Go to target settings -> Signing & Capabilities -> iCloud
`
Then inside your Info.plist, add this with your iCloud identifier and app name …
Issue #934
There are a few keychain wrappers around but for simple needs, you can write it yourself
Here is a basic implementation. I use actor to go with async/await, and a struct KeychainError to contain status code in case we want to deal with …
Issue #932
Add Share extension and Action extension respectively in Xcode. We can use the same code to both extension
I usually make a ShareView in SwiftUI with ShareViewModel to control the logic
struct ShareView: View {
@ …Issue #931
Portrait 1290 x 2796
Portrait 1242 x 2688
iOS 640 x 920 tvO 1920 x1080 pixels macOS 1280 x 800 pixels
Issue #930
Declare AppShortcutsProvider, note that appShortcuts uses @AppShortcutsBuilder syntax
import AppIntents
struct OurShortcutsProvider: AppShortcutsProvider {
static var shortcutTileColor: ShortcutTileColor = .lightBlue …Issue #922
EnvironmentValues Views in SwiftUI can react to configuration information that they read from the environment using an Environment property wrapper
Updated for iOS 17
Issue #920
For iOS 16 and macOS 13.0
TextEditor(text: $text)
.scrollContentBackground(.hidden)
For below, use [SwiftUI-Introspect](https://github.com/siteline/SwiftUI-Introspect)
TextEditor(text: $text)
.instrospectTextView {
$0. …Issue #919
WWDC23 introduces lots of new additions to SwiftUI, notably Metal shader support with these modifiers
Issue #918
Interesting SwiftUI Q&A during WWDC23
Q: With the new SwiftUI @Observable macro, are there any cases where ObservableObject would still be a better alternative?
A: Use ObservableObject when you need to …
Issue #916
WWDC23 brings new additions to SwiftUI
The scroll transition modifier is very similar to the visual effect modifier Curt used earlier for the welcome screen. It lets you apply effects to items in your scroll view.
I’m …
Issue #915
Here are my favorite iOS articles
Issue #911
Make an parallelTask function that wraps TaskGroup
public func parallelTask(@ParallelTaskBuilder builder: () -> [ParallelTaskBuilder.Work]) async {
await withTaskGroup(of: Void.self) { group in
for work in builder() { …Issue #910
let string = "Hello world"
string[string.startIndex...] // Hello world
string[..<string.endIndex] // Hello world
let string = "Hello world"
let range = string.startIndex ..< …Issue #908
When we add another UIWindow, then its rootViewController will decide the style of the status bar, not the rootViewController of the keyWindow anymore
The usual way to fix this is to defer the decision to the correct …
Issue #905
Protect mutable state with Swift actors
Actor reentrancy
Imagine we have two different concurrent tasks trying to fetch the same image at the same time. The first sees that there is no cache entry, proceeds to start downloading the …
Issue #904
Consider this code where we have an ObservableObject with fetch1 and async fetch2, and a fetch inside ContentView
Here the observation in Xcode 14
Issue #902
Siri can predict shortcuts to actions that a user may want to perform using your app, and suggest those shortcuts to the user in places such as …
Issue #901
https://com.example/.well-known/apple-app-site-association
Supporting Associated Domains
New format from iOS 13
Can also remove components section if we match all URLs
{
"applinks": { …Issue #894
Use a UIView as source view and set it in background
class ViewModel {
lazy var sourceView = UIView()
}
struct SourceView: UIViewRepresentable {
let viewModel: ViewModel
func makeUIView(context: Context) -> UIView { …Issue #884
When user taps on push notification, depending on app state
Checking UIScene.ConnectionOptions.notificationResponse?.notification.request.content.userInfo in scene(_:willConnectTo:options:)
Issue #880
From iOS 14, we can do Identity Pinning: How to configure server certificates for your app right from Info.plist
<key>NSAppTransportSecurity</key>
<dict>
<key>NSPinnedDomains</key> …Issue #879
Initialize Your CloudKit Schema During Development
let …Issue #874
From iOS 13, use UITabBarAppearance and UITabBarItemAppearance
let appearance = UITabBarAppearance()
let itemAppearance = UITabBarItemAppearance(style: .stacked)
itemAppearance.normal.badgeBackgroundColor = .clear
itemAppearance.normal. …Issue #873
Use assistant
let assistant = MCAdvertiserAssistant(serviceType: "my-service, discoveryInfo: nil, session: mcSession)
assistant.start()
let browser = MCBrowserViewController(serviceType: "my-service", session: mcSession) …Issue #856
Use PKPaymentRequest and PKPaymentAuthorizationViewController
@MainActor
final class WalletViewModel: NSObject, ObservableObject {
var canMakePayments: Bool {
PKPaymentAuthorizationViewController.canMakePayments()
} …Issue #847
We should use Dynamic Font Type as much as possible, as per Typography guide and https://www.iosfontsizes.com/
But in case we have to use a specific font, we can scale it with UIFontMetrics
import SwiftUI
import UIKit
extension Font { …Issue #843
This can be used in message bar input or some popover form. We use sizeThatFits to calculate the height so that it grow under certain height limit
import SwiftUI
import UIKit
struct MessageTextField: View {
let placeholder: String …Issue #835
I usually define ButtonStyle to encapsulate common styles related to buttons. Here we specify .frame(maxWidth: .infinity) to let this button take the whole width as possible
struct MyActionButtonStyle: ButtonStyle {
func makeBody( …Issue #824
Use a custom NavigationLink with EmptyView as the background, this failable initializer accepts Binding of optional value. This works well as the destination are made lazily.
extension NavigationLink where Label == EmptyView {
init …Issue #823
Make atomic components and compose them. Firstly with NavigationBar that has custom leading and trailing content, there we can customize padding.
import SwiftUI
struct NavigationBar<Leading: View, Trailing: View>: View {
@ …Issue #820
Use NSDataDetector to detect links, and NSMutableAttributedString to mark link range. Then we enumerateAttributes and build our Text
func attribute(string: String) -> Text {
guard let detector = try? NSDataDetector(types: …Issue #814
From iOS 14, TabView has the PageTabViewStyle that turns TabView into the equivalent UIPageViewController.
We can of course implement our own Pager but the simple DragGesture does not bring the true experience of a paging UIScrollView or …
Issue #811
Don’t add SwiftFormat as SPM package, instead use command line directly
if which swiftformat >/dev/null; then
swiftformat .
else
echo "warning: SwiftFormaat not installed, download from …Issue #809
Add a hidden overlay UIContextMenuInteraction. Provide preview in previewProvider and actions in actionProvider. Use @ViewBuilder to make declaring preview easy.
extension View {
func contextMenuWithPreview<Content: View>( …Issue #807
Don’t add SwiftLint via SPM, but just add a Run Script Build phrase
if which swiftlint >/dev/null; then
swiftlint
else
echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi …Issue #799
Besides coming up with a good idea and building the app, there are many other things you can do to boost your apps’ visibility
Twitter thread https://twitter.com/onmyway133/status/1387851727714635776 Thread reader …
Issue #794
I’ve been distributing my apps PastePal and Push Hero as a paid upfront apps on Appstore. I’ve quickly come to realize the importance of trials since many have requested a tryout before purchasing.
Manual sending out trials …
Issue #792
iOS 13 introduced Dark Mode with User Interface Style that makes it easy to support dark and light theme in our apps. Before we dive in, here are some official resources
Issue #790
Use UIImageWriteToSavedPhotosAlbum
Adds the specified image to the user’s Camera Roll album.
Let’s make an NSObject delegate class so we can perform target action to notify about completion
import UIKit
struct ImageService { …Issue #785
Calling mergeChanges on a managed object context will automatically refresh any managed objects that have changed. This ensures that your context always contains all the latest …
Issue #776
We need to use a custom Binding to trigger onChange as onEditingChanged is only called when the user selects the textField, and onCommit is only called when return or done button on keyboard is tapped.
import UIKit
import SwiftUI
import …Issue #775
My share sheet and action extension not showing up in iOS 14, built-in Xcode 12.3. The solution is to restart test device, and it shows up again.
Also make sure your extension targets have the same version and build number, and same …
Issue #749
Some apps want to support alternative app icons in Settings where user can choose to update app icon. Here’s some must do to make it work, as of Xcode 12.2
CFBundleIcons with both CFBundlePrimaryIcon and …Issue #747
Need to use Coordinator conforming to UITextViewDelegate to apply changes back to Binding
import SwiftUI
import UIKit
struct MyTextView: UIViewRepresentable {
@Binding
var text: String
final class Coordinator: NSObject, …Issue #746
From iOS 13, the default is to support multiple scene, so the the old UIApplicationDelegate lifecycle does not work. Double check your Info.plist for UIApplicationSceneManifest key
<key>UIApplicationSceneManifest</key> …Issue #742
Auto Layout has been around since macOS 10.7 and iOS 6.0 as a nicer way to do layouts over the old resizing masks. Besides some rare cases when we need to manually specify origins and sizes, Auto Layout is the preferred way to do …
Issue #703
Read When to refresh a receipt vs restore purchases in iOS?
From iOS 7, every app downloaded from the store has a receipt (for downloading/buying the app) at appStoreReceiptURL. When users purchases something via In App …
Issue #691
Supposed we want to present a ViewController, and there exist both UIToolbar in both the presenting and presented view controllers.
From iOS 13, the model style is not full screen and interactive. From UITests perspective there are 2 …
Issue #682
After has recently reminded about his updating APNs provider API which makes me realised a lot has changed about push notifications, both in terms of client and provider approach.
The HTTP/2-based Apple Push Notification service (APNs) …
Issue #673
To draw rounded 2 corners at top left and top right, let’s start from bottom left
let path = UIBezierPath()
// bottom left
path.move(to: CGPoint(x: 0, y: bounds.height))
// top left corner
path.addArc(withCenter: CGPoint(x: radius, y …Issue #671
Use adjustsFontForContentSizeCategory
A Boolean that indicates whether the object automatically updates its font when the device’s content size category changes.
If you set this property to YES, the element adjusts for a new …
Issue #670
To test for viewWillDisappear during UINavigationController popViewController in unit test, we need to simulate UIWindow so view appearance works.
final class PopTests: XCTestCase {
func testPop() {
let window = UIWindow(frame: …Issue #660
Apply tintColor does not seem to have effect.
datePicker.setValue(UIColor.label, forKeyPath: "textColor")
datePicker.setValue(false, forKey: "highlightsToday")
Issue #631
When your app moves to the background, the system …
Issue #603
Need to set correct frame for mask layer or UILabel, as it is relative to the coordinate of the view to be masked
let aView = UIView(frame: .init(x: 100, y: 110, width: 200, height: 100))
let textLayer = CATextLayer()
textLayer. …Issue #600
Use same CACurrentMediaTime
final class AnimationSyncer {
static let now = CACurrentMediaTime()
func makeAnimation() -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: "opacity")
animation. …Issue #598
It’s hard to see any iOS app which don’t use UITableView or UICollectionView, as they are the basic and important foundation to represent data. UICollectionView is very basic to use, yet a bit tedious for common use cases, but …
Issue #593
#if canImport(Combine) is not enough, need to specify in Other Linker Flags
OTHER_LDFLAGS = -weak_framework Combine
Issue #583
In UITests, we can use press from XCUIElement to test drag and drop
let fromCat = app.buttons["cat1"].firstMatch
let toCat = app.buttons["cat2"]
let fromCoordinate = fromCat.coordinate(withNormalizedOffset: CGVector(dx: 0, …Issue #582
Run on device, Xcode -> Debug -> View debugging -> Rendering -> Color blended layer
On Simulator -> Debug -> Color Blended Layer
Issue #580
Implement scene(_:openURLContexts:) in your scene delegate.
If the URL launches your app, you will get …
Issue #571
From CGFloat.pi / 2 to -CGFloat.pi / 2 + epsilon
Issue #570
@available(iOS 11.0, *)
override func viewSafeAreaInsetsDidChange() {
super.viewSafeAreaInsetsDidChange()
self.collectionView.reloadData()
}
Use …
Issue #569
From documentation https://developer.apple.com/documentation/uikit/uicollectionviewlayout/1617726-initiallayoutattributesforappear
This method is called after the prepare(forCollectionViewUpdates:) method and before the …
Issue #567
import UIKit
public protocol AdapterDelegate: class {
/// Apply model to view
func configure(model: Any, view: UIView, indexPath: IndexPath)
/// Handle …Issue #550
Issue #539
extension XCTestCase {
func takeScreenshot(name: String) {
let screenshot = XCUIScreen.main.screenshot()
let attach = XCTAttachment(screenshot: screenshot)
attach.lifetime = .keepAlways …Issue #538
UIToolbar -> _UIToolbarContentView -> _UIButtonBarStackVie
_UIToolbarContentView's width should equal 0
_UIToolbarContentView's height should equal 0
Workaround that fixes 1 warning
toolbar. …Issue #537
In xcodebuild, specify launch arguments.
You can specify this under Launch Arguments in Run action of the app scheme or UITest scheme
-AppleLanguages (jp) -AppleLocale (jp_JP)
(lldb) po ProcessInfo().arguments
▿ …Issue #536
extension UITextField {
func setLeftView(_ view: UIView, padding: CGFloat) {
view.translatesAutoresizingMaskIntoConstraints = true
let outerView = UIView()
outerView.translatesAutoresizingMaskIntoConstraints = …Issue #535
datePicker.setValue(UIColor.green, forKey: "textColor")
datePicker.setValue(false, forKey: "highlightsToday")
In iOS 14
if #available(iOS 14.0, *) {
datePicker.preferredDatePickerStyle = .wheels
datePicker.tintColor …Issue #530
Although UIImageView frame is correct, image is still cropped. Watch out for any layer.mask within view
Issue #529
It is up to you to decide how to use the indexPath parameter to identify a given decoration view. …
Issue #518
let userDefaults = UserDefaults(suiteName: suiteName)
userDefaults.removePersistentDomain(forName: suiteName)
https://developer.apple.com/documentation/foundation/userdefaults/1417339-removepersistentdomain
Calling this method is …
Issue #504
https://twitter.com/NeoNacho/status/1181245484867801088?s=20
There’s no way to have platform specific sources or targets today, so you’ll have to take a different approach. I would recommend wrapping all OS specific files in #if os and …
Issue #496
Read this Restoring Purchased Products to understand the purposes between the 2.
From iOS 7, every app downloaded from the store has a receipt (for downloading/buying the app) at appStoreReceiptURL. When users purchases something via In …
Issue #484
Use SwiftMonkey which adds random UITests gestures
Add to UITests target
target 'MyAppUITests' do
pod 'R.swift', '~> 5.0'
pod 'SwiftMonkey', '~> 2.1.0'
end
Issue #480
I use modulemap in my wrapper around CommonCrypto https://github.com/onmyway133/arcane, https://github.com/onmyway133/Reindeer
For those getting header not found, please take a look …
Issue #478
Dependencies used
Examples
Issue #473
Use UIScreen.didConnectNotification
NotificationCenter.default.addObserver(forName: UIScreen.didConnectNotification,
object: nil, queue: nil) { (notification) in
// Get the new screen …Issue #472
Use convenient code from Omnia
To make view height dynamic, pin UILabel to edges and center
import UIKit
final class ErrorMessageView: UIView {
let box: UIView = {
let view = UIView()
view. …Issue #471
let navigationController = UINavigationController(rootViewController: viewControllerA)
navigationController.pushViewController(viewControllerB, animated: true)
In view controller B, need to set hidesBottomBarWhenPushed in init
final class …Issue #470
Use NSTextAttachment inside NSAttributedString
extension UILabel {
func addTrailing(image: UIImage) {
let attachment = NSTextAttachment()
attachment.image = image
let attachmentString = NSAttributedString( …Issue #469
If there are lots of logics and states inside a screen, it is best to introduce parent and child container, and switch child depends on state. Each child acts as a State handler.
In less logic case, we can introduce a Scenario class that …
Issue #466
iOS
View Controller -> View Model | Logic Handler -> Data Handler -> Repo
Android
Activity -> Fragment -> View Model | Logic Handler -> Data Handler -> Repo
Issue #463
func zoom(location1: CLLocation, location2: CLLocation) {
let bounds = GMSCoordinateBounds(coordinate: location1.coordinate, coordinate: location2.coordinate)
let update = GMSCameraUpdate.fit(bounds, withPadding: 16)
mapView. …Issue #462
Using object, we don’t need to care about nil vs false like in UserDefaults, our object is the source of truth
class StoringHandler<T: Codable> {
private let key: Storage.Keys
private let storage = Deps.storage …Issue #461
With UIAlertController we can add buttons and textfields, and just that
func addAction(UIAlertAction)
func addTextField(configurationHandler: ((UITextField) -> Void)?)
To add custom content to UIAlertController, there are some …
Issue #460
extension UIView {
func findRecursively<T: UIView>(type: T.Type, match: (T) -> Bool) -> T? {
for view in subviews {
if let subview = view as? T, match(subview) {
return subview …Issue #459
Here are my notes when working with Push Notification
Register to receive push notification
registerForRemoteNotificationTypes is deprecated in iOS 8+
UIApplication.sharedApplication().registerForRemoteNotifications() …Issue #456
From WWDC 2018 What’s New in User Notifications
Instead, the notifications from your app will automatically start getting delivered.
Notifications that are delivered with provisional authorization will have a prompt like this on …
Issue #455
There are times we want to log if user can receive push notification. We may be tempted to merely use isRegisteredForRemoteNotifications but that is not enough. From a user ’s point of view, they can either receive push notification …
Issue #454
From documentation https://developer.apple.com/documentation/usernotificationsui
Customize how local and remote notifications appear on the user’s device by adding a notification content app extension to the bundle of your iOS app. Your …
Issue #452
Use UserNotifications framework
import FirebaseMessaging
import UserNotifications
final class PushHandler: NSObject {
private let center = UNUserNotificationCenter.current()
private let options: UNAuthorizationOptions = [.alert] …Issue #444
To avoid compiler error Unprintable ASCII character found in source file, from Swift 5, we can use isASCII.
Run this from the generator app that generates Swift code.
let normalized = weirdString.filter({ $0.isASCII })
For more check, see …
Issue #440
http://itunes.apple.com/[country]/app/[App–Name]/id[App-ID]?mt=8
For example https://apps.apple.com/nl/app/cutters/id1466739130
Issue #434
When calling collectionView.reloadData(), selected indexpath stays the same, but be aware that order of data may have changed
let selectedData = ...
let indexPathForSelectedData = ...
collectionView.scrollToItem(
at: …Issue #424
One confusing point here that people often do not realize is that even though the custom token itself expires after one hour, a modern client SDK authenticated …
Issue #422
To constrain views outside to elements inside UICollectionViewCell, we can use UILayoutGuide.
Need to make layout guide the same constraints as the real elements
let imageViewGuide = UILayoutGuide()
collectionView.addLayoutGuide( …Issue #421
private func maskCvcIfAny() {
guard
let view = paymentTextField.subviews.first(where: { !($0 is UIImageView) }),
let cvcField = view.subviews
.compactMap({ $0 as? UITextField })
.first(where: { $0.tag == 2 …Issue #414
Codable is awesome, but sometimes we just need to quickly get value in a deepy nested JSON. In the same way I did for Dart How to resolve deep json object in Dart, let’s make that in Swift.
See …
Issue #412
When the value of this property is true, the …
Issue #411
class ViewController: UIViewController, UICollectionViewDropDelegate, UICollectionViewDragDelegate {
// MARK: - UICollectionViewDragDelegate
func collectionView(_ collectionView: UICollectionView, …Issue #402
I want to test if a date has passed another date
let base = Date(timeIntervalSince1970: 1567756697)
XCTAssertEqual(validator.hasPassed(event: event, date: base), true)
My hasPassed is using Calendar.current
func minuteSinceMidnight(date: …Issue #395
Prefer static enum to avoid repetition and error. The Log should have methods with all required fields so the call site is as simple as possible. How to format and assign parameters is encapsulated in this Analytics.
import Foundation …Issue #387
Google Analytics is shutting down. From Firebase Analytics console, we can choose to upgrade to Google Analytics, no code change is needed.
https://support.google.com/firebase/answer/9167112?hl=en
In October 2019, we will start to sunset …
Issue #386
When it comes to right and bottom side, we should use negative values, and use lessThan, as it means less than a negative value
Issue #385
+ (BOOL)isJailbroken {
#if !(TARGET_IPHONE_SIMULATOR)
FILE *file = fopen( …Issue #377
OneSignal is an alternative for Parse for push notifications but the sdk has many extra stuff and assumptions and lots of swizzling.
We can just use Rest to make API calls. From https://github.com/onmyway133/Dust
Every official push …
Issue #376
https://github.com/onmyway133/Omnia/blob/master/Sources/Shared/Debouncer.swift
import Foundation
public class Debouncer {
private let delay: TimeInterval
private var workItem: DispatchWorkItem?
public init(delay: TimeInterval …Issue #375
final class LifecyclerHandler {
private var observer: AnyObject!
var action: (() -> Void)?
private let debouncer = Debouncer(delay: 1.0)
func setup() {
observer = NotificationCenter.default.addObserver( …Issue #374
Add accessibilityIdentifier to the parent view of GMSMapView. Setting directly onto GMSMapView has no effect
accessibilityIdentifier = "MapView"
let map = app.otherElements.matching(identifier: …Issue #373
UIButton.contentEdgeInsets does not play well with Auto Layout, we need to use intrinsicContentSize
final class InsetButton: UIButton {
required init(text: String) {
super.init(frame: .zero)
titleLabel?.textColor = . …Issue #371
Scrolling UIScrollView is used in common scenarios like steps, onboarding.
From iOS 11, UIScrollView has contentLayoutGuide and frameLayoutGuide
https://developer.apple.com/documentation/uikit/uiscrollview/2865870-contentlayoutguide …
Issue #369
Issue #368
See https://github.com/onmyway133/Omnia/blob/master/Sources/iOS/NSLayoutConstraint.swift
extension NSLayoutConstraint {
/// Disable auto resizing mask and activate constraints
///
/// - Parameter constraints: constraints to …Issue #365
import WebKit
import SafariServices
final class WebViewHandler: NSObject, WKNavigationDelegate {
var show: ((UIViewController) -> Void)?
let supportedSchemes = ["http", "https"]
func webView(_ webView: …Issue #364
AppFlowController.swift
import UIKit
import GoogleMaps
import Stripe
final class AppFlowController: UIViewController {
private lazy var window = UIWindow(frame: UIScreen.main.bounds)
func configure() {
GMSServices. …Issue #362
let tapGR = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
@objc private func handleTap(_ gr: UITapGestureRecognizer) {
didTouch?()
}
We need to use lazy instead of let for gesture to work
lazy var tapGR = …Issue #356
StripeHandler.swift
From Stripe 16.0.0 https://github.com/stripe/stripe-ios/blob/master/CHANGELOG.md#1600-2019-07-18
Migrates STPPaymentCardTextField.cardParams property type from STPCardParams to STPPaymentMethodCardParams
final class …Issue #353
When using STPPaymentCardTextField from stripe-ios, the default behavior is when we touch outside to dismiss keyboard, it checks and focus on number text field is it is invalid
STPPaymentCardTextField.m
- (STPFormTextField *) …Issue #350
Read Authenticate with Firebase on iOS using a Phone Number
Info.plist
<key>FirebaseAppDelegateProxyEnabled</key>
<string>NO</string>
Enable Capability -> Background …
Issue #347
Add a hidden UITextField to view hierarchy, and add UITapGestureRecognizer to activate that textField.
Use padding string with limit to the number of labels, and prefix to get exactly n characters.
DigitView.swift
import UIKit
final …Issue #346
We have FrontCard that contains number and expiration date, BackCard that contains CVC. CardView is used to contain front and back sides for flipping transition.
We leverage STPPaymentCardTextField from Stripe for working input fields, …
Issue #345
UIButton with system type has implicit animation for setTitle(_:for:)
Use this method to set the title for the button. The title you specify derives its formatting from the button’s associated label object. If you set both a title and an …
Issue #344
addSubview can trigger viewDidLayoutSubviews, so be careful to just do layout stuff in viewDidLayoutSubviews
This method establishes a strong reference to view and sets its next responder to the receiver, which is its new superview. …
Issue #343
Xcode 10.3 with iOS 13
sudo ln -s /Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/13.0 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport
Xcode 10.3 with iOS 13.1 …
Issue #339
For simple cases, we don’t need to. Let’s use urlCache
The URL cache for providing cached responses to requests within the session.
The URL Loading System caches responses both in memory and on disk, …
Issue #337
Normally we just present from any UIViewController in any UINavigationController in UITabBarController and it will present over tabbar
present(detailViewController, animated: true, completion: nil)
If we have animation with …
Issue #334
NSSecureCoding has been around since iOS 6 and has had some API changes in iOS 12
A protocol that enables encoding and decoding in a manner that is robust against object substitution attacks. …
Issue #333
In a traditional pager with many pages of content, and a bottom navigation with previous and next button. Each page may have different content, and depending on each state, may block the next button.
The state of next button should state …
Issue #329
Firstly, to make UIStackView scrollable, embed it inside UIScrollView. Read How to embed UIStackView inside UIScrollView in iOS
It’s best to listen to keyboardWillChangeFrameNotification as it contains frame changes for Keyboard in …
Issue #328
Sometimes we want to validate forms with many fields, for example name, phone, email, and with different rules. If validation fails, we show error message.
We can make simple Validator and Rule
class Validator {
func validate(text: …Issue #326
Traditionally, from Swift 4.2 we need guard let self
addButton.didTouch = { [weak self] in
guard
let self = self,
let product = self.purchasedProduct()
else {
return
self.delegate?.productViewController …Issue #325
UILabel as placeholder and move itoffsetX for translation is 10%Issue #324
view.addSubview(scrollView)
scrollView.addSubview(stackView)
NSLayoutConstraint.on([
scrollView.pinEdges(view: view),
stackView.pinEdges(view: scrollView)
])
NSLayoutConstraint.on([
stackView.widthAnchor.constraint(equalTo: …Issue #318
I do UI in code, and usually separate between View and ViewController.
class ProfileView: UIView {}
class ProfileViewController: UIViewController {
override func loadView() {
self.view = ProfileView()
}
}
But in places where …
Issue #315
extension PanCollectionViewController: UIGestureRecognizerDelegate {
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
let velocity = panGR.velocity(in: panGR.view)
return abs( …Issue #313
Push user-facing notifications to the user’s device from a server, or generate them locally from your app.
A class that animates changes to views and allows the dynamic modification …
Issue #313
Push user-facing notifications to the user’s device from a server, or generate them locally from your app.
A class that animates changes to views and allows the dynamic modification …
Issue #313
Push user-facing notifications to the user’s device from a server, or generate them locally from your app.
A class that animates changes to views and allows the dynamic modification …
Issue #313
Push user-facing notifications to the user’s device from a server, or generate them locally from your app.
A class that animates changes to views and allows the dynamic modification …
Issue #311
See Omnia https://github.com/onmyway133/Omnia/blob/master/Sources/iOS/UICollectionView.swift#L30
extension HorizontalUsersViewController: UIScrollViewDelegate {
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { …Issue #309
let placemark = MKPlacemark(coordinate: coordinate, addressDictionary: nil)
let mapItem = MKMapItem(placemark: placemark)
mapItem.name = shop.name
mapItem.openInMaps(launchOptions: [:])
Issue #307
import MapKit
let formatter = MKDistanceFormatter()
formatter.unitStyle = .abbreviated
formatter.units = .metric
distanceLabel.text = formatter.string(fromDistance: distance) // 700m, 1.7km
Issue #303
Instead of setting up custom framework and Playground, we can just display that specific view as root view controller
window.rootViewController = makeTestPlayground()
func makeTestPlayground() -> UIViewController {
let content = …Issue #302
final class CarouselLayout: UICollectionViewFlowLayout {
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
guard let attributes = super. …Issue #301
Make it more composable using UIViewController subclass and ThroughView to pass hit events to underlying views.
class PanViewController: UIViewController {
var animator = UIViewPropertyAnimator(duration: 0, curve: .easeOut)
lazy …Issue #288
Use this property to specify a …
Issue #280
Original post https://medium.com/fantageek/how-to-fix-wrong-status-bar-orientation-in-ios-f044f840b9ed
When I first started iOS, it was iOS 8 at that time, I had a bug that took my nearly a day to figure out. The issue was that the status …
Issue #258
I started iOS development when iOS 7 had been announced. And I have learned a bit, through working, advice from colleagues and the iOS community.
In this article, I’d like to share a lot of good practices by taking the example of a simple …
Issue #250
UITabBarItem subclasses from UIBarItem which has imageInsets. We need both top and bottom to avoid shrinking
viewController1.tabBarItem.imageInsets = UIEdgeInsets(top: 10, left: 0, bottom: -10, right: 0)
Issue #249
Making splash screen with LaunchScreen.storyboard is now the default way to do in iOS. Testing it with UITests is a bit tricky as this screen is showed the system, and if we test that, we are just testing the system.
What we should test is …
Issue #246
Use GMSMapStyle https://developers.google.com/maps/documentation/android-sdk/styling Export styling json from https://mapstyle.withgoogle.com/
let mapStyleUrl = Bundle.main.url(forResource: "mapStyle", withExtension: "json" …Issue #245
Original post https://medium.com/fantageek/my-favourite-wwdc-2018-sessions-363d3fc9c9d5
This year I failed the lottery ticket to WWDC, and I also missed the keynote live stream because I was sailing on the …
Issue #232
From https://github.com/xhamr/paintcode-path-scale with some updates
extension CGRect {
var center: CGPoint {
return CGPoint( x: self.size.width/2.0,y: self.size.height/2.0)
}
}
extension CGPoint {
func vector(to p1: …Issue #230
CAReplicatorLayer is a layer that creates a specified number of sublayer copies with varying geometric, temporal, and color transformations
Here we use instanceTransform which applies transformation matrix around the center of the …
Issue #229
let animation = CASpringAnimation(keyPath: #keyPath(CALayer.transform))
animation.fromValue = 0
animation.valueFunction = CAValueFunction(name: CAValueFunctionName.rotateZ)
animation.timingFunction = CAMediaTimingFunction(name: …Issue #228
CAAnimation is about presentation layer, after animation completes, the view snaps back to its original state. If we want to keep the state after animation, then the wrong way is to use CAMediaTimingFillMode.forward and …
Issue #227
final class SearchBox: UIView {
lazy var textField: UITextField = {
let textField = UITextField()
let imageView = UIImageView(image: R.image.search()!)
imageView.frame.size = CGSize(width: 20 + 8, height: 20) …Issue #226
Take screenshot
xcrun simctl io booted screenshot image.png
Record video
xcrun simctl io booted recordVideo video.mp4
Issue #225
<key>UIAppFonts</key>
<array>
<string>OpenSans-Bold.ttf</string>
<string>OpenSans-BoldItalic.ttf</string>
<string>OpenSans-ExtraBold.ttf</string>
<string> …Issue #224
let tabBarController = UITabBarController()
let navigationController1 = UINavigationController(rootViewController: viewController1)
let navigationController2 = UINavigationController(rootViewController: viewController2)
let …Issue #221
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>example.com</key>
<dict>
<key> …Issue #219
import UIKit
import Stripe
final class MainController: UIViewController {
func showPayment() {
let addCardViewController = …Issue #210
Depending on what features we want to achieve, we need to go with either AVFoundation or MediaPlayer framework. As someone who worked with many apps that involve media playback, here are some of my observations
Issue #209
Here are what I learn about reachability handling in iOS, aka checking for internet connection. Hope you will find it useful, too.
This post starts with techniques from Objective age, but many of the concepts still hold true
Issue #194
DispatchWorkItemIssue #183
func zoomInDouble(coordinate: CLLocationCoordinate2D) {
let region = mapView.region
let zoomInRegion = MKCoordinateRegion(
center: coordinate,
span: MKCoordinateSpan(
latitudeDelta: region.span. …Issue #182
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
guard let coordinate = view.annotation?.coordinate else {
return
}
if (view.annotation is MKClusterAnnotation) {
zoomInDouble( …Issue #181
final class AnnotationView: MKMarkerAnnotationView {
override init(annotation: MKAnnotation?, reuseIdentifier: …Issue #179
let rough = context.objectForKeyedSubscript("myObject")
myObject.toDictionary()
Issue #154
The most common UI element in iOS is UITableView, and the most common task is to display the UITableViewCell using the model.
Although the title specifies UITableViewCell, but the problem involves other views (UICollectionView, custom …
Issue #148
From https://github.com/devxoul/Pure/blob/master/Sources/Pure/FactoryModule.swift
public protocol FactoryModule: Module {
/// A factory for `Self`.
associatedtype Factory = Pure.Factory<Self>
/// Creates an instance of a …Issue #144
There are times we want the same UIViewController to look good when it’s presented modally or pushed from UINavigationController stack. Take a look at BarcodeScanner and the PR https://github.com/hyperoslo/BarcodeScanner/pull/82
When …
Issue #143
Today I was writing tests and get this error related to app idle
t = 23.06s Assertion Failure: <unknown>:0: Failed to scroll to visible (by AX action) Button, 0x6000003827d0, traits: 8858370049, label: 'cart', …Issue #138
Here is how to use R.swift in UITest target
Localizable.strings to UITest targettarget 'MyAppUITests' do
pod 'R.swift', '~> 4.0'
end
$(FRAMEWORK_SEARCH_PATHS) …Issue #137
Use a custom NavigationController
import UIKit
class NavigationController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
navigationBar.tintColor = .white
navigationBar.barStyle = .black …Issue #133
With dlopen we can make uses of some private frameworks. It will be fun
From iPhone X home button
#import <dlfcn.h>
// somewhere in viewDidLoad
dlopen([binaryPath cStringUsingEncoding:NSUTF8StringEncoding], RTLD_NOW);
UIView *const …Issue #124
We all know that there’s a potential crash with UIVisualEffectView on iOS 11. The fix is to not add sub views directly to UIVisualEffectView, but to its contentView. So we should change
effectView.addSubview(button)
to
effectView. …Issue #119
This is about collection update, how to provide correct IndexPath and a simple diffing algorithm
Issue #113
This is a follow up from my post Learning from Open Source: Using Playground on how to actually add a playground to your production project.
The idea is simple: create a framework so that Playground can access the code. This demo an iOS …
Issue #110
Medium version https://medium.com/@onmyway133/url-routing-with-compass-d59c0061e7e2
Apps often have many screens, and UIViewController works well as the basis for a screen, together with presentation and navigation APIs. Things are fine …
Issue #106
Every new architecture that comes out, either iOS or Android, makes me very excited. I’m always looking for ways to structure apps in a better way. But after some times, I see that we’re too creative in creating architecture, …
Issue #99
I’ve been searching for efficient ways to diff collections, here are some interesting papers that I find
Myers
Issue #98
The safeAreaLayoutGuide was introduced in iOS 11. And it is advised to stop using topLayoutGuide bottomLayoutGuide as these are deprecated.
To use safeAreaLayoutGuide, you need to do iOS version check
if #available(iOS 11.0, *) { …Issue #97
The Coordinator pattern can be useful to manage dependencies and handle navigation for your view controllers. It can be seen from BackchannelSDK-iOS, take a look at BAKCreateProfileCoordinator for example
@implementation …Issue #96
Another cool thing about ios-oss is how it manages dependencies. Usually you have a lot of dependencies, and it’s good to keep them in one place, and inject it to the objects that need.
The Environment is simply a struct that holds …
Issue #94
One thing I like about kickstarter-ios is how they use Playground to quickly protoyping views.
We use Swift Playgrounds for iterative development and styling. Most major screens in the app get a corresponding playground where we can see a …
Issue #92
Today I was upgrading Keychain to swift 4, and take this opportunity to fix the test. The tests pass on macOS, but on iOS, I get -25300 error for
var status = SecItemCopyMatching(query as CFDictionary, nil)
It is because there is no …
Issue #85
That’s the question I hear often when people are introduced to a new framework. It’s a valid concern. But it seems to me that they ask this just for fun. To my surprise, most people just don’t care, and the frameworks with …
Issue #64
Note: This applies to Firebase 4.0.4
Go to Member Center -> Certificates -> Production
You can now use 1 certificate for both sandbox and production environment

Issue #59
TL;DR: Don’t use nativeScale and nativeBounds, unless you’re doing some very low level stuff
From …
Issue #56



Issue #45
You should mock a location to ensure reliable test
Go to Xcode -> File -> New -> GPX File

It looks like
<?xml version="1.0"?>
<gpx version="1.1" creator="Xcode" …Issue #36
Usually in an app, we have these flows: onboarding, login, main. And we usually set OnboardingController, LoginController and MainController as the root view controller respectively depending on the state.
I find it useful to have the …
Issue #35
Auto Layout is awesome. Just declare the constraints and the views are resized accordingly to their parent ’s bounds changes. But sometimes it does not look good, because we have fixed values for padding, width, height, and even fixed …
Issue #33
I see that my answer to the question What’s the meaning of Base SDK, iOS deployment target, Target, and Project in xcode gets lots of views, so I think I need to elaborate more about it
Good read
Issue #32
iOS 9 introduces new ways for your app to work better, backed by your websites
If the app is already installed on a user’s device, the banner intelligently changes its action, …
Issue #24
There is Lighter View Controllers, and there is Lighter AppDelegate, too
Since working with iOS, I really like the delegate pattern, in which it helps us defer the decision to another party.
The iOS application delegates its event to …
Issue #23
Returns whether the constraints impacting the layout of the view incompletely specify the location of the view.
This method randomly changes the frame of a view with an ambiguous layout between …
Issue #22
In the beginning, people use frame and Autoresizing Mask, then they use Auto Layout, then iOS 9 encourages them to use NSLayoutAnchor, UILayoutGuide and UIStackView
For more convenient Auto Layout, check How to make Auto Layout more …
Issue #20
The other day I was doing refresh control, and I saw this Swift Protocols with Default Implementations as UI Mixins
extension Refreshable where Self: UIViewController
{
/// Install the refresh control on the table view
func …Issue #19
We need to care about security nowadays, here are some links I find useful to read more about this matter