How to declare escaping in completion in callback in Swift

Issue #464 typealias Completion = (Result<User, Error>) -> Void func validate(completion: @escaping Completion, then: (String, String, @escaping Completion) -> Void) {}

October 14, 2019 · 1 min · Khoa Pham

How to zoom to fit many coordinates in Google Maps in iOS

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.animate(with: update) }

October 14, 2019 · 1 min · Khoa Pham

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 · Khoa Pham

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 · Khoa Pham

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 · Khoa Pham

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, ....

October 11, 2019 · 6 min · Khoa Pham

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 · Khoa Pham

How to create watch only watchOS app

Issue #457 From Creating Independent watchOS Apps The root target is a stub, and acts as a wrapper for your project, so that you can submit it to the App Store. The other two are identical to the targets found in a traditional watchOS project. They represent your WatchKit app and WatchKit extension, respectively.

October 10, 2019 · 1 min · Khoa Pham

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...

October 10, 2019 · 2 min · Khoa Pham

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 · Khoa Pham

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....

October 10, 2019 · 1 min · Khoa Pham

How to use AnyHashable in Swift

Issue #453 From documentation A type-erased hashable value. DiscussionThe AnyHashable type forwards equality comparisons and hashing operations to an underlying hashable value, hiding its specific underlying type.You can store mixed-type keys in dictionaries and other collections that require Hashable conformance by wrapping mixed-type keys in AnyHashable instances let descriptions: [AnyHashable: Any] = [ AnyHashable("😄"): "emoji", AnyHashable(42): "an Int", AnyHashable(Int8(43)): "an Int8", AnyHashable(Set(["a", "b"])): "a set of strings" ] print(descriptions[AnyHashable(42)]!...

October 10, 2019 · 1 min · Khoa Pham

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 · Khoa Pham

How to flat map publisher of publishers in Combine

Issue #451 For some services, we need to deal with separated APIs for getting ids and getting detail based on id. To chain requests, we can use flatMap and Sequence, then collect to wait and get all elements in a single publish FlatMap Transforms all elements from an upstream publisher into a new or existing publisher. struct FlatMap<NewPublisher, Upstream> where NewPublisher : Publisher, Upstream : Publisher, NewPublisher.Failure == Upstream....

October 9, 2019 · 1 min · Khoa Pham

How to make container view in SwiftUI

Issue #450 Following the signatures of ScrollView and Group, we can create our own container public struct ScrollView<Content> : View where Content : View { /// The content of the scroll view. public var content: Content } extension Group : View where Content : View { /// The type of view representing the body of this view. /// /// When you create a custom view, Swift infers this type from your /// implementation of the required `body` property....

October 9, 2019 · 2 min · Khoa Pham

How to show web content as QR code in SwiftUI in watchOS

Issue #449 WatchKit does not have Web component, despite the fact that we can view web content https://www.imore.com/how-view-web-pages-apple-watch-watchos-5 A workaround is to show url as QR code import SwiftUI struct QRCodeView: View { let title: String let url: URL var body: some View { GeometryReader { geometry in VStack { self.makeImage(size: geometry.size) .padding(.top, 10) Text("Scan to open") .font(.system(.footnote)) }.navigationBarTitle(self.title) } } private func makeImage(size: CGSize) -> some View { let value = size....

October 8, 2019 · 1 min · Khoa Pham

How to load remote image in SwiftUI

Issue #448 Use ObservableObject and onReceive to receive event. URLSession.dataTask reports in background queue, so need to .receive(on: RunLoop.main) to receive events on main queue. For better dependency injection, need to use ImageLoader from Environment There should be a way to propagate event from Publisher to another Publisher, for now we use sink ImageLoader.swift import Combine import WatchKit class ImageLoader: ObservableObject { private var cancellable: AnyCancellable? let objectWillChange = PassthroughSubject<UIImage?, Never>() func load(url: URL) { self....

October 8, 2019 · 1 min · Khoa Pham

How to do navigation in SwiftUI in watchOS

Issue #447 NavigationView is not available on WatchKit, but we can just use NavigationLink List(services.map({ AnyService($0) })) { anyService in NavigationLink(destination: ItemsView(service: anyService.service) .navigationBarTitle(anyService.service.name) .onDisappear(perform: { anyService.service.requestCancellable?.cancel() }) ) { HStack { Image(anyService.service.name) .resizable() .frame(width: 30, height: 30, alignment: .leading) Text(anyService.service.name) } } } Adding NavigationLink to a View adds a round shadow cropping effect, which is usually not want we want. But we shouldn’t wrap Button as Button handles its own touch event, plus it has double shadow effect....

October 8, 2019 · 1 min · Khoa Pham

How to use protocol in List in SwiftUI

Issue #446 Suppose we have Service protocol, and want to use in List protocol Service { var name: String { get } } struct MainView: View { let services = [ Car() Plane() ] var body: some View { List(services) { service in HStack { Image(service.name) Text(service.name) } } } } This is not possible because item in List needs to conform to Identifiable Protocol type ‘Service’ cannot conform to ‘Identifiable’ because only concrete types can conform to protocols...

October 7, 2019 · 2 min · Khoa Pham

How to support Swift Package Manager for existing projects

Issue #445 How to add SPM Run swift package init Check enum for version for each platform https://developer.apple.com/documentation/swift_packages/supportedplatform/tvosversion Example https://github.com/onmyway133/Anchors/blob/master/Package.swift // swift-tools-version:5.1 import PackageDescription let package = Package( name: "Anchors", platforms: [ .macOS(.v10_11), .iOS(.v9), .tvOS(.v9) ], products: [ .library( name: "Anchors", targets: ["Anchors"]), ], targets: [ .target( name: "Anchors", dependencies: [], path: "Sources" ), .testTarget( name: "AnchorsTests", dependencies: ["Anchors"]), ], swiftLanguageVersions: [.v5] ) To test, swift test to test locally, this should validate Package....

October 7, 2019 · 1 min · Khoa Pham