How to use Swift
Issue #887 What’s new https://www.whatsnewinswift.com https://www.hackingwithswift.com/articles/249/whats-new-in-swift-5-7 https://www.hackingwithswift.com/articles/247/whats-new-in-swift-5-6
Issue #887 What’s new https://www.whatsnewinswift.com https://www.hackingwithswift.com/articles/249/whats-new-in-swift-5-7 https://www.hackingwithswift.com/articles/247/whats-new-in-swift-5-6
Issue #886 SwiftUI iOS 16 https://bigmountainstudio.github.io/What-is-new-in-SwiftUI/ https://swiftwithmajid.com/2022/06/07/what-is-new-in-swiftui-after-wwdc22/ https://www.hackingwithswift.com/articles/250/whats-new-in-swiftui-for-ios-16 SwiftUI https://www.hackingwithswift.com/articles/235/whats-new-in-swiftui-for-ios-15 https://www.hackingwithswift.com/articles/221/whats-new-in-swiftui-for-ios-14 https://talk.objc.io/collections/swiftui-layout-explained SwiftUI practices 8 Common SwiftUI Mistakes – and how to fix them! https://www.youtube.com/watch?v=qkcKTJhDyLs 5 Steps to Better SwiftUI Views https://www.youtube.com/watch?v=uC3X4FoielU SwiftUI tips and tricks https://www.hackingwithswift.com/quick-start/swiftui/swiftui-tips-and-tricks SwiftUI Tips https://www.youtube.com/watch?v=M2e1Z9enFHo Tips thread https://twitter.com/twostraws/status/1465801488920465414?s=20 Quick Friday tips https://twitter.com/search?src=typed_query&q=%22Quick%20Friday%20tip%22%20(from%3Ascottsmithdev Reference https://github.com/onmyway133/awesome-swiftui https://swiftontap.com/
Issue #885 Create NSBitmapImageRep with preferred size and draw NSImage onto that. Need to construct NSBitmapImageRep specifically instead of using convenient initializers like NSBitmapImageRep(data:), NSBitmapImageRep(cgImage:) to avoid device dependant resolution issue. extension NSImage { func pngData( size: CGSize, imageInterpolation: NSImageInterpolation = .high ) -> Data? { guard let bitmap = NSBitmapImageRep( bitmapDataPlanes: nil, pixelsWide: Int(size.width), pixelsHigh: Int(size.height), bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: .deviceRGB, bitmapFormat: [], bytesPerRow: 0, bitsPerPixel: 0 ) else { return nil } bitmap....
Issue #884 When user taps on push notification, depending on app state SceneDelegate Checking UIScene.ConnectionOptions.notificationResponse?.notification.request.content.userInfo in scene(_:willConnectTo:options:) app terminated: sometimes nil app in background: notification info UNUserNotificationCenter Checking UNNotificationResponse.notification.request.content.userInfo in userNotificationCenter(_:didReceive:withCompletionHandler:) app terminated: notification info app in background: notification info Read more https://stackoverflow.com/questions/60007715/launchoptions-always-nil-when-launching-from-a-push-notification https://stackoverflow.com/questions/42989932/difference-between-unusernotificationcenterdelegate-and-didreceiveremotenotifica
Issue #883 Read more https://www.objc.io/blog/2020/11/10/hstacks-child-ordering/ https://talk.objc.io/collections/swiftui-layout-explained https://rensbr.eu/blog/swiftui-escaping-closures/ https://rensbr.eu/blog/swiftui-render-loop/ https://movingparts.io/variadic-views-in-swiftui
Issue #882 In SwiftUI, .popover shows as popover on Mac and iPad, but as .sheet on iPhone (compact size class) We can use minWidth, minHeight to specify sizes on Mac and iPad. On iPhone, we can check and wrap it inside NavigationView. Setting navigationTitle without being embedded in NavigationView has not effect `` .popover(isPresented: $showsEdit) { EditSnippetView( snippet: snippet ) .frame(minWidth: 300, alignment: .topLeading) .navigationTitle("Tags") .modifier( EmbedInNavigationModifier() ) }
Issue #881 Specify optional value for List(selection:). This keeps selection on macOS, but not on iPad. On iPad each row in the List needs to be NavigationLink, no need for .tag. The selection is not updated, need to manually update with onTapGesture For List selection to work, make sure selection binding type matches. Preferablly using ID than Self Need to specify id in ForEach for List to infer tag. Otherwise, need to specify tag for cell struct Sidebaer: View { class ViewModel: ObservableObject { @Published var group: BookGroup?...
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> <dict> <key>awesome.apps.example.com</key> <dict> <key>NSIncludesSubdomains</key> <true/> <key>NSPinnedCAIdentities</key> <array> <dict> <key>SPKI-SHA256-BASE64</key> <string>12312312312xasdas123asdasdasdasdsad</string> </dict> </array> </dict> </dict> </dict> There are a few drawbacks The subdomains works for multiple part host as well, as long as it is 1 subdomain level Need to duplicate values in each Info.plist Need to duplicate values if the host differs Can’t use User Defined Settings variables in localized Info....
Issue #879 Setting Up Core Data with CloudKit Enable iCloud Enable CloudKit and Push Notifications Enable Remote Notifications in the Background Creating a Core Data Model for CloudKit Initialize Your CloudKit Schema During Development let container = NSPersistentCloudKitContainer(name: "Earthquakes") // Only initialize the schema when building the app with the // Debug build configuration. #if DEBUG do { // Use the container to initialize the development schema. try container.initializeCloudKitSchema(options: []) } catch { // Handle any errors....
Issue #878 Note that Explicit id is needed, although Book already conforms to Identifiable selection needs a default value class BookViewModel: ObservableObject { @Published var books: [Book] = [] @Published var selectedBooks: Set<Book> = [] } List(selection: $viewModel.selectedBooks) { ForEach(viewModel.books, id: \.self) { book in BookRow(book: book) } }
Issue #877 Over the course of making several SwiftUI apps, I’ve discovered quite a few hidden magic of SwiftUI that are quite fun. Here are 6 interesting SwiftUI features in View Builder many don’t 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...
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 import Combine 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?...
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’s Info.plist, or returns nil if no Editor type is declared. You can override it to customize the type of document that is created when, for instance, the user chooses New in the File menu....
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/
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
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?...
Issue #870 Building https://dev.to/dabit3/building-scalable-full-stack-apps-on-ethereum-with-polygon-2cfb Sidechain https://docs.polygon.technology/docs/home/new-to-polygon https://hackernoon.com/what-are-sidechains-and-childchains-7202cc9e5994 USDC Testnet https://mumbai.polygonscan.com/token/0x566368d78dbdec50f04b588e152de3cec0d5889f Mainnet https://polygonscan.com/token/0x2791bca1f2de4661ed88a30c99a7a9449aa84174 Faucet Testnet https://faucet.polygon.technology/
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]?...
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?...
Issue #867 Using https://github.com/ajamaica/Solana.Swift and the sendSPLToken method. Note that the from is the token account address and amount can have decimals solana.action.sendSPLTokens( mintAddress: MINT_ADDRESS, from: SENDER_TOKEN_ACCOUNT_ADDRESS, to: RECEIVER_WALLET_ADDDRESS, amount: UInt64(Float(amount) * units), allowUnfundedRecipient: true, onComplete: { result in continuation.resume(with: result) } ) We can also cross-reference to the solana web3.js library for how to create mint and transfer token import { clusterApiUrl, Connection, Keypair, LAMPORTS_PER_SOL } from '@solana/web3.js'; import { createMint, getOrCreateAssociatedTokenAccount, mintTo, transfer } from '....