How to use Codable to store preferences in Swift

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 init(key: Storage.Keys) { self.key = key load() } var object: T? { didSet { if let object = object { try? storage.save(object: object, key: key) } else { try? storage.clear(key: key) } } } private func load() { self....

October 11, 2019 · 1 min · 123 words · Khoa

How to custom UIAlertController in iOS

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 workarounds Add content onto UITextField Restyle UITextField and add custom content Subclass UIAlertController and handle UI in viewWillAppear By subclassing we can tweak the whole view hierarchy and listen to events like layout subviews, but this can be very fragile. Make custom UIViewController that looks like UIAlertController This is the correct way but takes too much time to imitate UIAlertController, and have to deal with UIVisualEffectView, resize view for different screen sizes and dark mode...

October 11, 2019 · 2 min · 222 words · Khoa

How to find subview recursively in Swift

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 } else { return view.findRecursively(type: type, match: match) } } return nil } }

October 11, 2019 · 1 min · 46 words · Khoa

How to deal with multiple scenarios with Push Notification in iOS

Issue #459 Here are my notes when working with Push Notification How to register Register to receive push notification registerForRemoteNotificationTypes is deprecated in iOS 8+ UIApplication.sharedApplication().registerForRemoteNotifications() Register to alert user through UI If your app displays alerts, play sounds, or badges its icon, you must call this method during your launch cycle to request permission to alert the user in these ways let types: UIUserNotificationType = [.Badge, .Sound, .Alert] let categories = Set<UIUserNotificationCategory>() let settings = UIUserNotificationSettings(forTypes: types, categories: categories) UIApplication....

October 11, 2019 · 6 min · 1214 words · Khoa

How to use Apple certificate in Xcode 11

Issue #458 For push notification, we can now use just Production Certificate for 2 environments (production and sandbox) instead of Development and Production certificates. Now for code signing, with Xcode 11 https://developer.apple.com/documentation/xcode_release_notes/xcode_11_release_notes we can just use Apple Development and Apple Distribution certificate for multiple platforms Signing and capabilities settings are now combined within a new Signing & Capabilities tab in the Project Editor. The new tab enables using different app capabilities across multiple build configurations....

October 11, 2019 · 1 min · 142 words · Khoa

How to use provisional notification in iOS 12

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 the notification itself. And this will help the users decide after having received a few notifications whether they want to keep getting these notifications or whether they want to turn them off It’s an automatic trial of the notifications from your app to help your users make a more informed decision about whether they want these notifications....

October 10, 2019 · 2 min · 281 words · Khoa

How to check if push notification is actually enabled in iOS

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 or not. But behind the scene, many factors are in the game. It can be that user has disabled push notification in app settings or in iOS Settings. It can also be that user enables push notification but disables all sound or banner display mechanism....

October 10, 2019 · 2 min · 289 words · Khoa

How to use UserNotificationsUI in iOS

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 extension manages a custom view controller, which you use to present the content from incoming notifications. When a notification arrives, the system displays your view controller in addition to, or in place of, the default system interface. https://developer.apple.com/documentation/usernotificationsui/customizing_the_appearance_of_notifications When an iOS device receives a notification containing an alert, the system displays the contents of the alert in two stages....

October 10, 2019 · 1 min · 166 words · Khoa

How to register for alert push notification in iOS

Issue #452 Use UserNotifications framework import FirebaseMessaging import UserNotifications final class PushHandler: NSObject { private let center = UNUserNotificationCenter.current() private let options: UNAuthorizationOptions = [.alert] func setup() { Messaging.messaging().delegate = self } func register() { center.requestAuthorization(options: options, completionHandler: { granted, error in print(granted, error) self.getSettings() }) } func getSettings() { center.getNotificationSettings(completionHandler: { settings in guard case let .authorized = settings.authorizationStatus, case let .enabled = settings.alertSetting, settings.alertStyle != .none else { return } // TODO }) } func handle(userInfo: [AnyHashable: Any]) { } } extension PushHandler: MessagingDelegate { func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) { print(fcmToken) } func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) { print(remoteMessage) } } @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application( _ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { completionHandler(....

October 10, 2019 · 1 min · 169 words · Khoa

How to fix unreadable ASCII characters in Swift

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 Character https://developer.apple.com/documentation/swift/character/3127011-isletter Watch out for Delete/House symbol ⌂ code 127 (0x7f) The above does not seem to work, use find to find  character (copy Sublime Text to see 0x7f character)...

October 7, 2019 · 1 min · 83 words · Khoa

How to get url of app on the iOS AppStore

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

October 3, 2019 · 1 min · 6 words · Khoa

How to handle UICollectionView reloadData with selected index path

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: indexPathForSelectedData, at: .centeredHorizontally, animated: false )

September 30, 2019 · 1 min · 36 words · Khoa

How to use Firebase ID token

Issue #424 https://medium.com/@jwngr/demystifying-firebase-auth-tokens-e0c533ed330c 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 with that custom token will stay authenticated beyond that hour! What happens under the hood is that the custom token is sent to the Firebase Auth service in exchange for an ID token and refresh token pair which are used to keep the client SDK authenticated...

September 17, 2019 · 2 min · 249 words · Khoa

How to constrain to views inside UICollectionViewCell in iOS

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(imageViewGuide) NSLayoutConstraint.on([ imageViewGuide.topAnchor.constraint(equalTo: collectionView.topAnchor, constant: 16), imageViewGuide.heightAnchor.constraint(equalTo: collectionView.heightAnchor, multiplier: 0.5) ]) NSLayoutConstraint.on([ loadingIndicator.centerXAnchor.constraint(equalTo: collectionView.centerXAnchor), loadingIndicator.centerYAnchor.constraint(equalTo: imageViewGuide.centerYAnchor) ])

September 17, 2019 · 1 min · 47 words · Khoa

How to secure CVC in STPPaymentCardTextField in Stripe for iOS

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 && ($0.accessibilityLabel ?? "").lowercased().contains("cvc") }) else { return } cvcField.isSecureTextEntry = true } where tag is in STPPaymentCardTextFieldViewModel.h typedef NS_ENUM(NSInteger, STPCardFieldType) { STPCardFieldTypeNumber, STPCardFieldTypeExpiration, STPCardFieldTypeCVC, STPCardFieldTypePostalCode, }; Also, need to check accessibilityLabel in STPPaymentCardTextField.m - (NSString *)defaultCVCPlaceholder { if (self.viewModel.brand == STPCardBrandAmex) { return STPLocalizedString(@"CVV", @"Label for entering CVV in text field"); } else { return STPLocalizedString(@"CVC", @"Label for entering CVC in text field"); } }

September 16, 2019 · 1 min · 96 words · Khoa

How to easily parse deep json in Swift

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 https://github.com/onmyway133/Omnia/blob/master/Sources/Shared/JSON.swift public func resolve<T>(_ jsonDictionary: [String: Any], keyPath: String) -> T? { var current: Any? = jsonDictionary keyPath.split(separator: ".").forEach { component in if let maybeInt = Int(component), let array = current as?...

September 12, 2019 · 1 min · 177 words · Khoa

How to speed up GMSMarker in Google Maps for iOS

Issue #412 Google Maps with a lot of pin, and no clustering can have bad performance if there are complex view in the marker. The workaround is to use manual layout and rasterization shouldRasterize When the value of this property is true, the layer is rendered as a bitmap in its local coordinate space and then composited to the destination with any other content. Shadow effects and any filters in the filters property are rasterized and included in the bitmap....

September 10, 2019 · 2 min · 345 words · Khoa

How to support drag and drop in UICollectionView iOS

Issue #411 See DragAndDrop example class ViewController: UIViewController, UICollectionViewDropDelegate, UICollectionViewDragDelegate { // MARK: - UICollectionViewDragDelegate func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] { let controller = leftController let provider = NSItemProvider( object: controller.imageForCell(indexPath: indexPath) ) let dragItem = UIDragItem(itemProvider: provider) dragItem.localObject = indexPath return [dragItem] } // MARK: - UICollectionViewDropDelegate func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) { let destinationIndexPath: IndexPath if let indexPath = coordinator....

September 10, 2019 · 1 min · 114 words · Khoa

How to test Date with timezone aware in Swift

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: Date) -> MinuteSinceMidnight { let calendar = Calendar.current let start = calendar.startOfDay(for: date) return Int(date.timeIntervalSince(start)) / 60 } But the minute is always having timezone applied. Even if I try with DateComponents func minuteSinceMidnight(date: Date) -> MinuteSinceMidnight { let components = calendar....

September 6, 2019 · 2 min · 230 words · Khoa

How to do simple analytics in iOS

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 import Firebase import FirebaseAnalytics struct Analytics { enum Parameter: String { case studentId = "student_id" case classId = "class_id" case url = "url" } enum Property: String { case grantLocation = "grant_location" } enum Name: String { case login case logOut = "log_out" case enroll } struct Log { private func log(_ name: Name, parameters: [Parameter: String] = [:]) { let mapped: [String: String] = Dictionary(uniqueKeysWithValues: parameters....

September 4, 2019 · 1 min · 198 words · Khoa