How to use ViewBuilder in SwiftUI

Issue #877 Over the course of making several SwiftUI apps, I鈥檝e discovered quite a few hidden magic of SwiftUI that are quite fun. Here are 6 interesting SwiftUI features in View Builder many don鈥檛 know are even possible 馃く View protocol with enum Struct is not the only way to describe #SwiftUI views. Learn how you can achieve the same thing with just enum Conform primitive type to View protocol You can also conform any value type or primitive type to View protocol...

April 11, 2022 路 2 min 路 Khoa Pham

How to debounce TextField search in SwiftUI

Issue #876 Make a dedicate DebounceObject to debounce (or throttle). Then we can even observe with onChange on the debouncedText or just use it directly to sort public final class DebounceObject: ObservableObject { @Published var text: String = "" @Published var debouncedText: String = "" private var bag = Set<AnyCancellable>() public init(dueTime: TimeInterval = 0.5) { $text .removeDuplicates() .debounce(for: .seconds(dueTime), scheduler: DispatchQueue.main) .sink(receiveValue: { [weak self] value in self?.debouncedText = value }) ....

March 26, 2022 路 1 min 路 Khoa Pham

How to create document based macOS app

Issue #875 Read newDocument This method calls openUntitledDocumentAndDisplay(_:). Read openUntitledDocumentAndDisplay The default implementation of this method calls defaultType to determine the type of new document to create, calls makeUntitledDocument(ofType:) to create it, then calls addDocument(_:) to record its opening. Read defaultType The default implementation of this method returns the first Editor type declared by the CFBundleDocumentTypes array in the application鈥檚 Info.plist, or returns nil if no Editor type is declared....

March 19, 2022 路 1 min 路 Khoa Pham

How to add dot indicator to tab bar item in iOS

Issue #874 From iOS 13, use UITabBarAppearance and UITabBarItemAppearance let appearance = UITabBarAppearance() let itemAppearance = UITabBarItemAppearance(style: .stacked) itemAppearance.normal.badgeBackgroundColor = .clear itemAppearance.normal.badgeTextAttributes = [.foregroundColor: UIColor.red] profileViewController.tabBarItem.badgeValue = "鈼" Read more https://emptytheory.com/2019/12/31/using-uitabbarappearance-for-tab-bar-changes-in-ios-13/

March 15, 2022 路 1 min 路 Khoa Pham

How to use Multipeer Connectivity

Issue #873 Use assistant let assistant = MCAdvertiserAssistant(serviceType: "my-service, discoveryInfo: nil, session: mcSession) assistant.start() let browser = MCBrowserViewController(serviceType: "my-service", session: mcSession) browser.delegate = self present(browser, animated: true) Manual let advertiser = MCNearbyServiceAdvertiser(peer: localPeerID, discoveryInfo: nil, serviceType: self.serviceType) advertiser.startAdvertisingPeer() let browser = MCNearbyServiceBrowser(peer: localPeerID, serviceType: self.serviceType) browser.startBrowsingForPeers() Enable in Info.plist <key>NSLocalNetworkUsageDescription</key> <string>Enable local network discovery to use Peer Share</string> <key>NSBonjourServices</key> <array> <string>_my-service._tcp</string> <string>_my-service._udp</string> </array> Read more https://www.hackingwithswift.com/example-code/networking/how-to-create-a-peer-to-peer-network-using-the-multipeer-connectivity-framework https://www.toptal.com/ios/collusion-ios-multipeerconnectivity

March 15, 2022 路 1 min 路 Khoa Pham

How to generate Polygon wallet account in Swift

Issue #871 Use libraries https://github.com/argentlabs/web3.swift https://github.com/bswags/web3keystore import web3 import web3keystore import KeychainAccess private final class KeyStorage: EthereumKeyStorageProtocol { enum Key: String { case privateKey case phrase } private let keychain = Keychain(service: "com.example.myapp") func storePrivateKey(key: Data) throws { try keychain.set(key, key: Key.privateKey.rawValue) } func loadPrivateKey() throws -> Data { if let data = try keychain.getData(Key.privateKey.rawValue) { return data } else { throw EthereumKeyStorageError.failedToLoad } } var phrase: String? { get { try?...

February 24, 2022 路 2 min 路 Khoa Pham

How to make simple Plist builder with resultBuilder in Swift

Issue #869 We can use PropertyListEncoder from Swift 4 let encoder = PropertyListEncoder() encoder.outputFormat = .xml let data = try encoder.encode(model) Or we can manually do with resultBuilder style Declare @resultBuilder for PlistBuilder that can support if else check import Foundation @resultBuilder enum PlistBuilder { static func buildBlock(_ components: PlistNode...) -> [PlistNode] { components } static func buildBlock(_ components: [PlistNode]...) -> [PlistNode] { components.flatMap { $0 } } static func buildEither(first component: [PlistNode]) -> [PlistNode] { component } static func buildEither(second component: [PlistNode]) -> [PlistNode] { component } static func buildOptional(_ component: [PlistNode]?...

February 18, 2022 路 2 min 路 Khoa Pham

How to generate JWT token for App Store Connect API in Swift

Issue #868 Use JWTKit and code from AppStoreConnect library import JWTKit public struct Credential { let issuerId: String let privateKeyId: String let privateKey: String public init( issuerId: String, privateKeyId: String, privateKey: String ) { self.issuerId = issuerId self.privateKeyId = privateKeyId self.privateKey = privateKey } func generateJWT() throws -> String { guard let signer = try? JWTSigner.es256( key: ECDSAKey.private(pem: privateKey)) else { throw AppStoreConnectError.invalidJWT } let payload = Payload( issueID: IssuerClaim(value: issuerId), expiration: ExpirationClaim( value: Date( timeInterval: 2 * 60, since: Date() ) ), audience: AudienceClaim( value: "appstoreconnect-v1" ) ) guard let jwt = try?...

February 16, 2022 路 1 min 路 Khoa Pham

How to make simple async URLSession in Swift

Issue #864 Since async URLSession.shared.data is available in iOS 15+, we can build a custom one with withCheckedThrowingContinuation import UIKit enum HTTPMethod: String { case get = "GET" case post = "POST" } extension URLSession { func asyncData( with url: URL, method: HTTPMethod = .get, headers: [String: String] = [:], body: Data? = nil ) async throws -> Data { var request = URLRequest(url: url) request.httpMethod = method.rawValue request.allHTTPHeaderFields = [ "Content-Type": "application/json" ] request....

February 7, 2022 路 1 min 路 Khoa Pham

How to check SPL token balance on Solana

Issue #863 We will check USDC token balance on Solana testnet. Firstly, we will use https://usdcfaucet.com/ to airdrop some USDC tokens into our wallet. Secondly, we check USDC token mint address on testnet cluster using Solana Explorer https://explorer.solana.com/address/CpMah17kQEL2wqyMKt3mZBdTnZbkbfx4nqmQMFDP5vwp?cluster=testnet Then we make an RPC call to POST https://api.testnet.solana.comhttps://api.testnet.solana.com using method getTokenAccountsByOwner, passing our wallet address and the token mint address { "jsonrpc": "2.0", "id": 1, "method": "getTokenAccountsByOwner", "params": [ "53THxwqa9qF3cn46wHVKbGMM8hUpZDJE5jS3T1qVL5bc", { "mint": "CpMah17kQEL2wqyMKt3mZBdTnZbkbfx4nqmQMFDP5vwp" }, { "encoding": "jsonParsed" } ] } The response looks like below....

February 7, 2022 路 2 min 路 Khoa Pham

How to use subscript in Swift

Issue #861 Make it easy to access common cases, for example UserDefaults extension UserDefaults { enum Key: String { case hasBackup } subscript(key: Key) -> Bool { get { bool(forKey: key.rawValue) } set { set(newValue, forKey: key.rawValue) } } } UserDefaults[.hasBackup] = true

February 5, 2022 路 1 min 路 Khoa Pham

How to encode JSON dictionary into JSONEncoder

Issue #860 JSONEncoder deals with type-safe, so we need to declare an enum JSONValue for all possible types. We also need a custom initializer to init JSONValue from a JSON Dictionary import Foundation enum JSONValue { case string(String) case int(Int) case double(Double) case bool(Bool) case object([String: JSONValue]) case array([JSONValue]) } extension JSONValue: Encodable { public func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() switch self { case .string(let string): try container....

February 4, 2022 路 2 min 路 Khoa Pham

How to parse Apple Pay PKPayment in Swift

Issue #859 To parse PKPayment and used with Wyre CreateAppleOrder API, we can declare some Encodable structs import PassKit import Foundation struct PaymentObject: Encodable { var billingContact: Contact? var shippingContact: Contact? var token: JSONValue } extension PaymentObject { struct Contact: Encodable { var addressLines: [String]? var country: String? var countryCode: String? var familyName: String? var givenname: String? var locality: String? var postalCode: String? var administrativeArea: String? var subAdministrativeArea: String? var subLocality: String?...

February 4, 2022 路 1 min 路 Khoa Pham

How to pop multiple level with NavigationView and NavigationLink in SwiftUI

Issue #858 Use isActive and isDetailLink(false) Use Introspect .introspectNavigationController { nav in self.nav = nav } Read more https://www.cuvenx.com/post/swiftui-pop-to-root-view

January 27, 2022 路 1 min 路 Khoa Pham

How to generate Solana wallet acount in Swift

Issue #857 Use Solana.swift and Mnemonic seed phrase. For production, change endpoint to mainnet import UIKit import Solana import KeychainAccess enum SolanaError: Swift.Error { case accountFailed case unauthorized } final class SolanaClient { static let shared = SolanaClient() final class SolanaClient { static let shared = SolanaClient() private let solana: Solana private let accountStorage = KeychainAccountStorage() private let seedPharser = SeedPhraser() private let endpoint: RPCEndpoint = .devnetSolana private let network: NetworkingRouter init() { self....

January 26, 2022 路 2 min 路 Khoa Pham

How to use Apple Pay in iOS

Issue #856 Use PKPaymentRequest and PKPaymentAuthorizationViewController @MainActor final class WalletViewModel: NSObject, ObservableObject { var canMakePayments: Bool { PKPaymentAuthorizationViewController.canMakePayments() } func showApplePay(amount: Amount, from window: UIWindow) { let request = PKPaymentRequest() request.supportedNetworks = [PKPaymentNetwork.amex, .discover, .masterCard, .visa] request.countryCode = "US" request.currencyCode = "USD" request.merchantIdentifier = "merchant.\(Bundle.main.bundleIdentifier!)" request.merchantCapabilities = .capability3DS let item = PKPaymentSummaryItem(label: "Add Cash", amount: amount.toNsDecimal) request.paymentSummaryItems = [item] guard let vc = PKPaymentAuthorizationViewController(paymentRequest: request) else { return } vc.delegate = self window....

January 17, 2022 路 1 min 路 Khoa Pham

How to show QR code in SwiftUI

Issue #855 Use CoreImage to generate QR image import SwiftUI import CoreImage.CIFilterBuiltins struct QRView: View { let qrCode: String @State private var image: UIImage? var body: some View { ZStack { if let image = image { Image(uiImage: image) .resizable() .interpolation(.none) .frame(width: 210, height: 210) } } .onAppear { generateImage() } } private func generateImage() { guard image == nil else { return } let context = CIContext() let filter = CIFilter....

January 15, 2022 路 1 min 路 Khoa Pham

How to not encode with Enum key in Swift

Issue #854 If you use enum case as key in Dictionary, JSONEncoder will encode it as Array. For example enum Vehicle: String, Codable { case car case truck } struct Container: Codable { var map: [Vehicle: String] } struct Container2: Codable { var map: [String: String] } let container = Container(map: [ .car: "Car 1" ]) let container2 = Container2(map: [ "car": "Car 1" ]) let data = try! JSONEncoder().encode(container) print(String(data: data, encoding: ....

January 10, 2022 路 2 min 路 Khoa Pham

How to disable with ButtonStyle in SwiftUI

Issue #853 With ButtonStyle, the disabled modifier does not seem to work, we need to use allowsHitTesting. import SwiftUI struct ActionButtonStyle: ButtonStyle { func makeBody(configuration: Configuration) -> some View { HStack { Text("Button") } .padding() .disabled(true) // does not work .allowsHitTesting(false) } } We need to call disabled outside, after buttonStyle. In case we have onTapGesture on the entire view, touching on that disabled button will also trigger our whole view action, which is not what we want....

December 4, 2021 路 1 min 路 Khoa Pham

How to query document id in array in Firestore

Issue #852 Supposed we have Book object struct Book: Identifiable, Codable, Hashable { @DocumentID var id: String? } We should use FieldPath instead of id for query let booksRef: CollectionReference = ... let ids: [String] = ... booksRef .whereField( FieldPath.documentID(), in: ids )

November 28, 2021 路 1 min 路 Khoa Pham