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) {}
Issue #464 typealias Completion = (Result<User, Error>) -> Void func validate(completion: @escaping Completion, then: (String, String, @escaping Completion) -> Void) {}
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) }
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....
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...
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 } }
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, ....
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....
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.
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...
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....
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....
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)]!...
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(....
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....
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....
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....
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....
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....
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...
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....