Post

Replies

Boosts

Views

Activity

Change Navigation Text Title Color on Different SwiftUI Views
Hi I reviewed this post: How to change navigation title color in swiftUI This seems to work fine if the intention is to apply the title color across an application. I would like to apply a different text title color selectively depending on the View being shown. And in some instances revert back to the color depending on the light and dark themes. Same result occurs using a viewmodifier or simply using onAppear and onDisappear with the title color is applied to all views. And if you do modify it in onDisappear, when you navigate back to another view which changes the color onAppear it has the same color as the previous view. The only way I've found this to work is using UIViewControllerRepresentable and handling the viewWillAppear and viewWillDisappear something like this: NavigationBarView( viewWillAppear: { nav in nav.navigationBar.largeTitleTextAttributes = [.foregroundColor: UIColor.white] }, viewWillDisappear: { nav in nav.navigationBar.largeTitleTextAttributes = nil } ) Has anyone been successful in getting a different title text color to apply to different views using a modifier or onAppear and onDisappear? Appreciate any guidance.
1
0
1.1k
Apr ’24
TabView and Full Screen Background Image
Hi I have a TabView and I would like a background image to cover the full screen. Here is the code I'm struggling with: struct ContentView: View { var body: some View { ZStack { Image("background-image") .resizable() .scaledToFill() .edgesIgnoringSafeArea(.all) TabView { AssetsView() .tabItem { Label("Assets", systemImage: "books.vertical.fill") } FavouriteView() .tabItem { Label("Favourite", systemImage: "star.fill") } } } } No matter what I try, I can't seem to get my "background-image" to display. I thought I might just have the background image only on AssetsView but that wasn't successful either. Any ideas would be appreciated.
1
1
449
Apr ’24
Array of Protocols and Subscript
Hi I have an array of protocols and would like to retrieve items from the array based on an enum. Something like this: enum ServiceType: String {    case car    case boat } protocol ServiceDescriptor {    var contact: String { get }    var type: ServiceType { get } } struct CarService: ServiceDescriptor {    let contact: String    let type: ServiceType } struct BoatService: ServiceDescriptor {    let contact: String    let type: ServiceType } class Repair {     init(allowedRepairs: [ServiceDescriptor]) {         self.allowedRepairs = allowedRepairs     }     let allowedRepairs: [ServiceDescriptor]     subscript(type: ServiceType) -> ServiceDescriptor? {        get {            return allowedRepairs.first(where: { $0.type == type })        }     } } let carService = CarService(contact: "Fred", type: .car) let boatService = BoatService(contact: "Jane", type: .boat) let repair = Repair(allowedRepairs: [carService, boatService]) print(repair.allowedRepairs[type: ServiceType.boat]). // error I end up with errors in Playgrounds as: no exact matches in call to subscript  found candidate with type '(ServiceType) -> Array.SubSequence' (aka '(ServiceType) -> ArraySlice< ServiceDescriptor >') The following works: print(repair.allowedRepairs[0]) I'm obviously coming about this the wrong way, I wanted to avoid a dictionary i.e let allowedRepairs: [ServiceType: ServiceDescriptor] because that would lend itself to assigning the wrong ServiceDescriptor to a ServiceType and it kinda duplicates the data. Is there a another way to have a custom argument in subscript instead of int? Many thanks
3
0
1.4k
Apr ’22
Enterprise SSO Extension for iOS
Hi I've built an SSO extension for my app. Now I would like to update the authsrv:login.myhost.com with additional associated domains generated by the MDM. The video here at 9:10 mark references the MDM associated domain ApplicationAttributes for iOS as the way to go. https://developer.apple.com/videos/play/tech-talks/301/ Is it just a matter of including: com.apple.developer.associated-domains.mdm-managed=YES in the entitlement file for both the app and the extension and having the MDM push down something like this in the profile? <dict> <key>AssociatedDomains</key> <array> <string>authsrv:login.myhost2.com</string> </array> </dict> Appreciate any guidance.
0
0
956
Feb ’22
UserDefaults and SSO Extensions
Hi Have a question around extensions and app group capabilities. I have an existing app using UserDefaults and if I want to introduce an SSO extension; the extension doesn't use or need any of the data created by the app and saved to UserDefaults. Will the app still have access to the UserDefaults or do I have move to UserDefaults(suiteName: "group.com.YourCompany.YourApp") even if UserDefaults is only used by the app? Many thanks
2
0
978
Feb ’22
XCTest Ambiguous type name
Hi I've create a couple of files that are in the build target and "checked" the box to include these files in the test target. Here are the files in the build and test targets. DefaultValue+Extension.swift extension Bool { public enum False: DefaultValue { public static let defaultValue = false    }    public enum True: DefaultValue {     public static let defaultValue = true } } extension String { public enum Empty: DefaultValue {     public static let defaultValue = "" } } DefaultValuePropertyWrapper.swift public protocol DefaultValue { associatedtype Value: Decodable static var defaultValue: Value { get } } @propertyWrapper public struct Default<T: DefaultValue> { public var wrappedValue: T.Value public init() {   self.wrappedValue = T.defaultValue    } } extension Default: Decodable { public init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer()   self.wrappedValue = try container.decode(T.Value.self) } } extension Default: Encodable where T.Value: Encodable { public func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer()   try container.encode(self.wrappedValue) } } extension Default: Equatable where T.Value: Equatable {} extension Default: Hashable where T.Value: Hashable{} extension KeyedDecodingContainer { public func decode<T>(_ type: Default<T>.Type, forKey key: Key) throws -> Default<T> where T: DefaultValue { try decodeIfPresent(type, forKey: key) ?? .init() } } Running the unit test I encounter a several errors which I haven't been able to resolve. Here is my swift file with only the test target checked. DefaultValueTest.swift import XCTest @testable import MyFramework class DefaultValueTests: XCTestCase { override func setUpWithError() throws { } override func tearDownWithError() throws { } struct Person: Decodable { let userId: Int       let name: String       @Default<String.Empty> var nickName: String @Default<Bool.False> var isEnabled: Bool   @Default<Bool.True> var isAdmin: Bool } func testDefaultValues() throws {     let json = """       {       "userId": 1,          "name": "John" }       """ do {       let result = try JSONDecoder().decode(Person.self, from: json.data(using: .utf8)!)          XCTAssertTrue(result.nickname.isEmpty) XCTAssertFalse(result.isEnabled) XCTAssertTrue(result.isAdmin) } catch let error {       print("Error: \(error.localizedDescription)")         XCTFail() } }        The Person structure in DefaultValueTest.swift complains of the following: Type DefaultValueTests.Person does not conform to protocol Decodable nickName Ambiguous type name 'Empty' in 'String' isEnabled Ambiguous type name 'False' in 'Bool' isAdmin Ambiguous type name 'True' in 'Bool' When I build the framework and use it another project, everything works as expected... Appreciate any advice 🙏
1
0
1k
Jan ’22
HStack Alignments
Hi First SwiftUI app and spent a few hours trying to fix the alignment with the following layout. struct ContentView: View {     var body: some View {          VStack {             Text("About My Data")                 .font(.title)                 .fontWeight(.heavy)                 .multilineTextAlignment(.center)                 .padding()                         Spacer().frame(height: 64)             HStack {                 Image(systemName: "network")                     .font(.system(size: 36.0))                     .foregroundColor(.blue)                 VStack(alignment: .leading) {                     Text("Network Support")                         .font(.headline)                         .fontWeight(.bold)                     Text("Download your data from anywhere.")                         .font(.body)                         .foregroundColor(.gray)                         .multilineTextAlignment(.leading)                 }             }.padding()             Spacer().frame(height:24)             HStack {                 Image(systemName: "hand.raised.fill")                     .font(.system(size: 36.0))                     .foregroundColor(.blue)                VStack(alignment: .leading) {                     Text("Data Privacy")                         .font(.headline)                         .fontWeight(.bold)                     Text("Scanned certificates are never stored on the device.")                         .font(.body)                         .foregroundColor(.gray)                         .multilineTextAlignment(.leading)                 }             }.padding()         }     } } struct ContentView_Previews: PreviewProvider {     static var previews: some View {         ContentView()     } } You can see that the HStack alignments are off, the first (showing the network image) seems to have a extra padding , not sure how to correct it if anyone has some suggestions. Many thanks
3
0
1.7k
Dec ’21
SecItemAdd with kSecAttrAccessControl Error
Hi I'm trying to add to the Keychain with access control flags. However the OSStatus returns -50 One or more parameters passed to a function were not valid. Here is the function I've written causing the error: public func addItem(value: Data, forKey: String, accessControlFlags: SecAccessControlCreateFlags? = nil) { guard !forKey.isEmpty else {     return    } var query: [String: Any] = [kSecClass as String: kSecClassGenericPassword, kSecAttrService as String: Bundle.main.bundleIdentifier!, kSecAttrAccount as String: forKey, kSecValueData as String: value, kSecAttrSynchronizable as String: false kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlock] // Check if any access control is to be applied. if let accessControlFlags = accessControlFlags { var error: Unmanaged&lt;CFError&gt;?       guard let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, accessControlFlags, &amp;error) else { return } query[kSecAttrAccessControl as String] = accessControl    } let status = SecItemAdd(query as CFDictionary, nil) guard status != errSecDuplicateItem else { return } guard status == errSecSuccess else { let message = SecCopyErrorMessageString(status, nil) as String? ?? "Unknown error" print(message) return } } Any ideas why this might be occurring, if kSecAttrAccessControl is not added to the query parameter, then it works fine. Thanks
6
0
2.3k
Sep ’21
UserDefaults on App Launch
Hi On first launch (after download) of my app I display a "terms and conditions" consent screen. When the user taps agree, I set a Bool value in UserDefaults, so on next launch, the user is not prompted again. Pretty stock standard approach. I've had some users report that if the app is in the background for an extended period of time, the "terms and conditions" screen will re-appear when brought back into the foreground. But if the app was terminated after use and then re-launched, then behaviour is as expected - the "terms and conditions" screen is not shown. Is the better approach to use a file instead? Thanks
5
0
2.1k
Aug ’21
Semaphore Wait After Creating UIButton
Hi In this snippet, I've already added a button, the onDisplay action simply adds another UIButton with an addAction event to the view controller @IBAction func onDisplay(_ sender: UIButton) { let semaphore = DispatchSemaphore(value: 1)     var didComplete = false     addButton("hello world") { result in         print("result: \(result)")         didComplete = result         semaphore.signal()     }     if semaphore.wait(timeout: .now() + 5) == .timedOut {         print("timeout: \(didComplete)")     }     print("didComplete: \(didComplete)") } func addButton(_ message: String, completion: @escaping (Bool) -> Void) {     let button = UIButton(type: .system)     button.frame = CGRect(x: 100, y: 100, width: 100, height: 40)     button.backgroundColor = .systemBlue     button.setTitle(message, for: .normal)     button.titleLabel?.tintColor = .white     button.addAction(UIAction(handler: { action  in             completion(true)     }), for: .touchUpInside)     view.addSubview(button) } What I'm expecting to happen, is the new "hello world" button get created (which it does). If the user does nothing for 5 seconds (semaphore timeout), then print timeout: false. If the user tapped the button, this would print result: true in the completion closure. But what happens when I don't touch the button is didComplete: false prints out (the last line) and the semaphore.wait never gets invoked. How do I make the semaphore execute it's wait operation? Been struggling with this for days 😞
5
0
2.2k
Jun ’21
Custom UIView not appearing on ViewController
Hi I have a custom UIView contained xib which is in an xcframework. The view has a timeout property which removes itself from the super view if it expiries. If the view does expiry, it fires a delegate which the function can observe using the KVC approach. What I'm experiencing is my function adds the view to the view controller ok, but doesn't display it until the function completes or throws an error. Here is a snippet of what I have described: // MARK: Contained in custom xcframework class MyView: UIView { var delegate: VerificationHandler? required init?(coder aDecoder: NSCoder) {         super.init(coder: aDecoder)         initialize()     }     override init(frame: CGRect) {         super.init(frame: frame)         initialize()     } func initialize() { let bundle = Bundle(for: type(of: self))      let uvNib = UINib(nibName: String(describing: type(of: self)), bundle: bundle)      let uvView = uvNib.instantiate(withOwner: self, options: nil).first as! UIView addSubview(uvView) Timer.scheduledTimer(withTimeInterval: TimeInterval(10), repeats: false) { [self] timer in             timer.invalidate()             delegate?.verification(didContinue: false)             removeFromSuperview()       } } } protocol VerificationHandler { func verification(didContinue: Bool) } class VerificationResult: NSObject {     @objc dynamic var value: Bool     init(_ value: Bool) {         self.value = value     } } public enum MyEnum { } public extension MyEnum { private static var verificationResult: VerificationResult = VerificationResult(false) public static func myFunction(_ viewController: UIViewController) throws -> MyObject { if let viewController = viewController { let view = MyView(frame: viewController.view.frame) view.delegate = self as? VerificationHandler viewController.view.addSubview(view)  let semaphore = DispatchSemaphore.init(value: 0) // observe the change occurring in the view which creates the verificationResult. var result: Bool let kvc = verificationResult.observe(\.value, options: .new) { _, change in result = change.newValue! // didContinue semaphore.signal() } semaphore.wait() if !result { throw MyError.timeout } return MyObject(...) } } extension MyEnum: VerificationHandler {     func verification(didContinue: Bool) {         MyEnum.verificationResult = VerificationResult(didContinue)     } } // MARK: View controller app code class ViewController: UIViewController { override func viewDidLoad() {     super.viewDidLoad() } @IBAction func onClick(_ sender: UIButton) { do { // this call is where the custom view from the xcframework should appear       let result = try MyEnum.myFunction(self)       }       catch let error {       print(error.localizedDescription)       } } } I'm using the semaphore to wait for the timer in MyView to fire which would cause the KVC to invoke. Not sure if this is the best way, but I'm blocked and can't figure out why the view only appears after an Error is thrown from myFunc. Any guidance appreciated.
1
0
1.9k
Jun ’21
CryptoKit SecureEnclave and LAContext
Hi I want to prompt for FaceID or TouchID before creating the private key in the Secure Enclave. And again when the key is recreated. I might be misinterpreting the documentation wrong, but I thought passing in LAContext instance to the authenticationContext parameter does this for you in both create and recreate use cases. For example: swift let authContext = LAContext() let accessControl = SecAccessControlCreateWithFlags( nil, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, [.privateKeyUsage, .biometryCurrentSet], nil)! let key0 = try! SecureEnclave.P256.Signing.PrivateKey( accessControl: accessControl, authenticationContext: authContext) let key1 = try! SecureEnclave.P256.Signing.PrivateKey( dataRepresentation: key0.dataRepresentation, authenticationContext: authContext) I was expecting a biometry prompt to appear twice, on create and on recreate CryptoKit operations - no authentication prompt appears on an iPhoneX 14.3 with FaceID enrolled and enabled. Same result in the simulator. Read a few articles all suggesting the above code snippet is what you need to do, but I'm not seeing the desired result. Appreciate any help with this 🙏
1
0
1.2k
Feb ’21
Optional Protocol Type
HiI have a protocol as follows:protocol Profile: Codable, Identifiable { var id: String { get } var name: String { get } }With 2 implemenations as follows:struct Customer: Profile { let id: String let name: String let country: String } struct Contractor: Profile { let id: String let name: String let trade: String let companyName: String }I have a struct that encapsulates either the customer or contractor, but I don't what type of profile it will be at initialization time. So something like:final class UserData: ObservableObject, Codable { var account: Profile? }But the code doesn't compile with the error:Protocol 'Profile' can only be used as a generic constraint because it has Self or associated type requirements.How I'd like to use UserData is by:var user = UserData() user.account = getAccount() func getAccount() -&gt; Profile? { // decode JSON from file, returning a Custoemr or Contractor return Customer(id: "123", name: "Bill", country: "USA") }I'm struggling to assign account to an optional protocol. Appreciate any help and guidence.Thanks
4
0
935
Feb ’20
view sheet on first launch
HiI'm trying to display a sheet when the app first launches, similiar to when you upraded iOS to 13 and tapped say reminders.But I'm struggling to get with working with SwiftUI, here is a snippet of the code. It essentially crashes the app.import SwiftUI struct ContentView: View { @State private var showingSheet = false var body: some View { return self.sheet(isPresented: $showingSheet) { RegisterHome() } } } struct RegisterHome: View { var body: some View { NavigationView { Text("Register") .navigationBarTitle("Register") } } }Any thoughts would be very much appreciated.Thanks, Craig
3
0
1.4k
Dec ’19