Explore the art and science of app design. Discuss user interface (UI) design principles, user experience (UX) best practices, and share design resources and inspiration.

All subtopics

Post

Replies

Boosts

Views

Activity

App branding in navigation bar on every screen.
I am seeking guidance regarding the inclusion of app branding on the navigation controller across all screens within our application. Although it appears that Apple doesn't typically recommend this practice, our client has specifically requested the addition of branding elements. Can you please advise if it is permissible to implement such branding, and whether doing so would affect the app review process? The apple guideline state: "Ensure branding always defers to content. Using screen space for an element that does nothing but display a brand asset can mean there’s less room for the content people care about. Aim to incorporate branding in refined, unobtrusive ways that don’t distract people from your experience." Source: https://developer.apple.com/design/human-interface-guidelines/branding
1
0
298
Nov ’24
Is [NSKeyedUnarchiver unarchiveObjectWithFile:] reentrant?
I am experiencing strange crashes in my (ObjC) code, that insinuate some memory corruption (mostly running SHA256 decryption for file data in my code there's a // return object that was stored in encrypted file - (id) objectFromEncryptedFile:(NSString *)filePath { // read MYCrypto object that includes encrypted object of any class MYCrypto *encData = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; // decrypt, unarchive and return return [encData objectFromEncryptedData:encData.data]; } That seems to be called from different queues that are not synchronized. It came to me that maybe NSKeyedUnarchiver is not "thread safe" and maybe unarchiveObjectWithFile is not reentrant? Couldn't find anything in the normal documentation, but most of the old docs are no longer searchable. Can someone shed light on this?
0
0
293
Nov ’24
Core Data Error - "NSCocoaErrorDomain" - code: 134060
Hi, I am implementing the synchronisation of SwiftData with CloudKit as described in the Apple Documentation titled - "Syncing model data across a person’s devices." My app runs fine on iPhone without activating CloudKit under "Signing and Capabilities" option. But when activated, I get a CoreData error with a code: 134060. My app is in development stage. The following is the code snippet for your reference taken from the main structure adopting the App protocol. init() { do { #if DEBUG let schema = Schema([ Debit.self, Credit.self, ]) let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false) // Use an autorelease pool to make sure Swift deallocates the persistent // container before setting up the SwiftData stack. try autoreleasepool { let desc = NSPersistentStoreDescription(url: modelConfiguration.url) let opts = NSPersistentCloudKitContainerOptions(containerIdentifier: "iCloud.com.sureshco.MyFirstApp") desc.cloudKitContainerOptions = opts // Load the store synchronously so it completes before initializing the CloudKit schema. desc.shouldAddStoreAsynchronously = false if let mom = NSManagedObjectModel.makeManagedObjectModel(for: [ Debit.self, Credit.self, ]) { let container = NSPersistentCloudKitContainer(name: "MyFirstApp", managedObjectModel: mom) container.persistentStoreDescriptions = [desc] container.loadPersistentStores {_, err in if let err { fatalError(err.localizedDescription) } } // Initialize the CloudKit schema after the store finishes loading. try container.initializeCloudKitSchema() // Remove and unload the store from the persistent container. if let store = container.persistentStoreCoordinator.persistentStores.first { try container.persistentStoreCoordinator.remove(store) } } } #endif sharedModelContainer = try ModelContainer(for: schema, configurations: [modelConfiguration]) } catch { fatalError(error.localizedDescription) } } Any help will be greatly appreciated! Regards Suresh.
0
0
392
Nov ’24
I get these errors every time: 'App' is ambiguous for type lookup in this context
import SwiftUI import RealmSwift @main struct UniqueHolidayApp: App { init() { migrateRealmIfNeeded() } var body: some Scene { WindowGroup { ContentView() } } private func migrateRealmIfNeeded() { let config = Realm.Configuration( schemaVersion: 1, migrationBlock: { migration, oldSchemaVersion in if oldSchemaVersion < 1 { // Realm will handle changes automatically for simple additions/removals } } ) Realm.Configuration.defaultConfiguration = config } }
0
0
313
Nov ’24
When using the animation, the CPU usage rises to around 20-25%.
I'm new to developing with SwiftUI and I created a Pomodoro app for macOS that runs in the menu bar. I added 4 animations and when the user selects the snow animation, it starts snowing on the screen. But the app uses 20%-30% of the CPU and has high energy consumption. I can't reduce it and I couldn't find a solution. // snow animation import SwiftUI struct SnowflakeView: View { @State private var flakeYPosition: CGFloat = -100 @State private var isAnimating = false private let flakeSize: CGFloat = CGFloat.random(in: 10...30) private let flakeColor: Color = Color( red: Double.random(in: 0.8...1), green: Double.random(in: 0.9...1), blue: Double.random(in: 1...1), opacity: Double.random(in: 0.6...0.8) ) private let animationDuration: Double = Double.random(in: 1...3) private let flakeXPosition: CGFloat = CGFloat.random(in: 0...310) var body: some View { Text("❄️") .font(.system(size: flakeSize)) .foregroundColor(flakeColor) .position(x: flakeXPosition, y: flakeYPosition) .onAppear { if !isAnimating { withAnimation(Animation.linear(duration: animationDuration).repeatForever(autoreverses: false)) { flakeYPosition = 280 + 50 } isAnimating = true } } } } I also have how I run the animation below. ZStack { ForEach(0..<10, id: \.self) { index in if selectedAnimal == "Snow" { SnowflakeView() } else if selectedAnimal == "Rain" { RainDropAnimation() }else if selectedAnimal == "Leaf"{ LeafFallAnimation() }else if selectedAnimal == "Confetti"{ ConfettiAnimation() } } }
0
0
402
Nov ’24
NWListener, NWConnection, not accepting connections
I'm using NWListener with NWConnection. This code work great and I am able to start the listener and successfully receive connections in Xcode preview. However, when I build/run on my phone, the listener does not seem to accept connections from the network. If the app sends a message to itself on the phone, it is received, but if I send a message to that ip/port from another network device, it is not accepted/received. Any help or suggestions appreciated. import Foundation import Network import Combine @Observable class UDPListener3 { var listener: NWListener? var queue = DispatchQueue.global(qos: .userInitiated) var messageReceived: Data? private(set) var isReady: Bool private(set) var listening: Bool = false private(set) var receiving: Bool = false private(set) var port: UInt16 = 0 init () { isReady = false listening = false receiving = false messageReceived = nil listener = nil } func GetPort() { var portText = "\(String(describing: listener!.port))" portText = portText.replacingOccurrences(of: "Optional(", with: "") portText = portText.replacingOccurrences(of: ")", with: "") portText = portText.replacingOccurrences(of: ",", with: "") port = UInt16(portText)! if let testPort = listener?.port?.rawValue { self.port = testPort } } func config(port: Int) { if port > 0 { configinit(port: NWEndpoint.Port(integerLiteral: NWEndpoint.Port.IntegerLiteralType(port))) } else { configinit(port: nil) } } func configinit(port: NWEndpoint.Port?) { // conifigure and create listener let params = NWParameters.tcp params.allowFastOpen = true if port == nil { self.listener = try? NWListener(using: params, on: .any)//port) } else { self.listener = try? NWListener(using: params, on: port!) } if listener != nil { GetPort() self.listening = true self.listener?.stateUpdateHandler = { [self] update in switch update { case .ready: self.isReady = true print("*Listener.ready on port \(String(describing: self.listener?.port))") GetPort() case .failed: // Announce we are no longer able to listen self.listening = false self.isReady = false print("*Listener.failed on port \(port)") case .cancelled: // Announce we are no longer able to listen self.listening = false self.isReady = false print("*Listener.canceled on port \(port)") default: print("*Listener default connecting to port \(port)... \(self.listener!.state)") } print() } self.listener?.newConnectionHandler = { connection in print("@called listener.newConnectionHandler") self.createConnection(connection: connection) } // start listening self.listener?.start(queue: self.queue) GetPort() } else { print("unable to start listener") } } func createConnection(connection: NWConnection) { connection.stateUpdateHandler = { (newState) in switch (newState) { case .ready: print(" ...Connection.ready")// - \(connection)") self.receive(connection) case .cancelled: print(" ...Connection.cancelled")// - \(connection)") case .failed: print(" ...Connection.failed")// - \(connection)") default: print(" ...Connection.default: \(connection.state)")// - \(connection)") } } print(" ...connection starting") connection.start(queue: .global()) } func receive(_ connection: NWConnection) { print() print(" ...connection receiving") // respond 200 received self.respond(on: connection) //connection.receiveMessage() { [self] data, context, isComplete, error in //<-- this would not return until timeout expired?? connection.receive(minimumIncompleteLength: 20000, maximumLength: 200000) { [self] data, context, isComplete, error in receiving = true /* Check what we have */ var message = "" if data != nil { message = String(decoding: data!, as: UTF8.self) } else { message = "" } // ERROR if let unwrappedError = error { print(" >>ERROR: received in \(#function) - \(unwrappedError)") receiving = false return } // NO DATA guard let data = data else { print(" >>NO DATA with context - \(String(describing: context))") receiving = false return } // NOT COMPLETE if !isComplete { print(" >>NOT COMPLETE with context - \(String(describing: context))") //return } // RECEIVED A MESSAGE if message != "" { self.messageReceived = data print(" ...received data - \(String(describing: context)) \(String(describing: data))") receiving = false connection.cancel() return } // keep receiving, self.receive(connection) } } } func respond(on connection: NWConnection) { let response = """ HTTP/1.1 200 OK Content-Length: 2 OK """ connection.send( content: response.data(using: .utf8), completion: .idempotent ) } func cancel() { self.listener?.cancel() self.listener = nil self.listening = false self.isReady = false print("listener disabled") } }
0
0
315
Nov ’24
IOS18 update
Finally updated my phone lastnight and I honestly wish I had NEVER bothered! Apple, what on earth is going on with your design team?! It’s a nightmare!!!!!! incsnt find anything, my photos are a nightmare when I knew wheee everything was. Now I have to try and work out how to find things more when it wasn’t ideal during a consultation with clients as I looked incompetent. The settings for passwords, battery etc have all been changed aswell and the pull down part for locking/bluetooth/aeroplane modes are all stupid aswell. Overall, extremely unsatisided with the overall update. I stayed with Apple because of the convenience of knowing the layout. I switched once to android and hated it because it had a different layout and I didnt like it having to start again when I’m already so busy. i lasted 24 hours with that phone before taking it back and upgrading back to Apple. Since the new layout and since I’m due an upgrade, there’s now nothing stopping me as your customer from leaving and now getting an android phone because I now find the upgrade difficult to navigate. If I could change it back I would. Overall dissatisfied and now willing to upgrade to another Apple next month.
0
0
243
Nov ’24
Exception occurred during startRunning and stopRunning calls using AVCaptureSession
I called the viewWillDisappear method in UIViewController AVCaptureSession *session = self.session; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ if (!session.running) { [session startRunning]; } }); I called the viewWillDisappear method dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ AVCaptureSession *session = self.session; if (session && session.running) { [session stopRunning]; } }); But when the user exits the background and returns to the current page, clicking 'Return' will cause an exception Abnormal information: #36 Thread SIGSEGV SEGV_ACCERR libdispatch.dylib _dispatch_source_set_timer + 32 one PrivacyAccounting 0x00000001a5ede000 + 533590244180685288 two PrivacyAccounting 0x00000001a5ede000 + 533590244180685288 three PrivacyAccounting 0x00000001a5ede000 + 1236823037899193652 four libdispatch.dylib 0x000000018ea01000 + 3414669699500290324 libsystem_pthread.dylib _pthread_wqthread + 14360117738498687264
0
0
161
Nov ’24
18.2 Beta. How to disable! EYESORE and DISTRACTING NOISE!
MY iphone just updated to Beta 18. Now there are what appears to be category pictures next to each email as displayed on the phone. It is an eyesore and distracting to see or follow emails cleanly with this feature. Ok to have those pictures if people categorize or choose categorize option, BUT I DO NOT. Does anyone know how to disable this odd and useless picture? I have tried LIST VIEW option, but it did nothing. Thank you!
1
2
598
Nov ’24
Can I Implement an Exit Button in an iOS App?
I am an iOS app developer and I have a question regarding the implementation of an exit button in an iOS app. I remember reading in the past that Apple does not recommend this practice, but I couldn’t find any explicit policy on this matter in the current Human Interface Guidelines. Could you please clarify whether it is acceptable to implement an exit button in an iOS app according to the latest guidelines? Any references or official documentation would be greatly appreciated.
3
0
573
Nov ’24
Setting unable seach for app
In the previous version it was possible in the setting to search directly for an app, and then go on the setting and for example disable the notifications. In iOS 18 you cannot do it anymore, you have to click on notification, and then search by scrolling the full list. It would be nice if you can add again the search feature for the apps in the settings.
0
0
283
Nov ’24
Issues with UserDefault boolean
Hi, I have a view that should do the following: Set up and confirm a passcode upon account creation. Verify passcode if signing in. Reset passcode if prompted. With the code below, functions 1 and 2 are working. However, I'm having an issue with function 3. I am able to declare the reset UserDefault on a previous view so that the proper logic occurs, which is to read in the input, and then confirm it. However, it is not working as intended. In this code here: else if reset { UserDefaults.standard.set(passcode, forKey: "new-passcode") UserDefaults.standard.set(false, forKey: "reset-passcode") passcode = "" } I store the new passcode, set reset to false, and clear the passcode so it can be entered again to confirm. The code does not run as intended however. The title does not change and I'm unsure if it is actually storing the passcode. And, when re-entering, it does not change the view as it should by setting view = .someView. I'm assuming there is just flaw in my logic but I'm not sure how to resolve this. Below is the full code. Please let me know if any further clarification is needed. struct EnterPasscode: View { @State var title = "" @State var passcode = "" @State var message = "" @State var buttonState = false @Binding var view: Views var body: some View { Group { Spacer() .frame(height: 50) Text(title) .font(.system(size: 36)) .multilineTextAlignment(.center) .frame(height: 50) Spacer() if passcode != "" { Text("\(passcode)") .font(.system(size: 24)) .frame(height: 25) } else { Spacer() .frame(height: 25) } Spacer() .frame(height: 50) PasscodeKeypad(passcode: $passcode) Spacer() if message != "" { Text(message) .frame(height: 25) .foregroundStyle(Color.red) } else { Spacer() .frame(height: 25) } Spacer() WideButton(text: "Continue", buttonFunction: .functional, openView: .enterPasscode, view: .constant(.enterPasscode), buttonState: $buttonState) .onChange(of: buttonState) { oldState, newState in if buttonState { let passcodeSet = UserDefaults.standard.bool(forKey: "passcode-set") let storedPasscode = UserDefaults.standard.string(forKey: "passcode") let reset = UserDefaults.standard.bool(forKey: "passcode-reset") let newPasscode = UserDefaults.standard.string(forKey: "new-passcode") print(reset) if passcode.count == 4 { if storedPasscode == nil { if newPasscode == nil { UserDefaults.standard.set(passcode, forKey: "new-passcode") passcode = "" } else if passcode == newPasscode { UserDefaults.standard.set(passcode, forKey: "passcode") UserDefaults.standard.set(true, forKey: "passcode-set") view = .someView } } else if reset { UserDefaults.standard.set(passcode, forKey: "new-passcode") UserDefaults.standard.set(false, forKey: "reset-passcode") passcode = "" } else if newPasscode != nil { if passcode == newPasscode { UserDefaults.standard.set(passcode, forKey: "passcode") view = .someView } } } checkPasscodeStatus() buttonState = false } } Spacer() if !UserDefaults.standard.bool(forKey: "passcode-reset") && UserDefaults.standard.bool(forKey: "passcode-set") { Button(action: { view = .verifyPhone }) { Text("Forgot passcode?") .foregroundStyle(.black) } } Spacer() .frame(height: 25) } .onAppear() { checkPasscodeStatus() } .frame(width: UIScreen.main.bounds.width - 50) } func checkPasscodeStatus() { let passcodeSet = UserDefaults.standard.bool(forKey: "passcode-set") let storedPasscode = UserDefaults.standard.string(forKey: "passcode") let reset = UserDefaults.standard.bool(forKey: "passcode-reset") if reset { title = "Enter new passcode" } else if passcodeSet { title = "Enter Passcode" } else if storedPasscode != nil && storedPasscode != "" { title = "Confirm Passcode" } else { title = "Select a 4 Digit Passcode" } } } struct WideButton: View { @State var text: String @State var buttonFunction: ButtonType @State var openView: Views? @Binding var view: Views @Binding var buttonState: Bool var body: some View { Button(action: { buttonPressed() }, label: { ZStack { RoundedRectangle(cornerRadius: 5) .fill(Color.black) .frame(width: UIScreen.main.bounds.width - 50, height: 50) Text(text) .foregroundColor(.white) } }) } func buttonPressed() { switch buttonFunction { case .openView: view = openView! case .functional: buttonState = true } } } enum ButtonType { case openView case functional }
3
0
497
Nov ’24
New iOS 18
The format of photos on the new iOS 18 and its updates is HORRIBLE. Not userfriendly, not easy to navigate, not even appealing to the eye. I can’t even see my favorites album anymore and have to search for it every time. In short, I hate it. Well done Apple
2
0
479
Nov ’24
Behavioral change in iOS 18 related to SCEP profile downloads from the browser.
Hi Team, We have noticed a behavioral change in iOS 18 related to SCEP profile downloads from the browser. In current flow, we are using Cisco ISE as SCEP server. While testing in iOS 18, we have observed that before communicating to SCEP server iOS is asking to download the SCEP server certificate. This differs from iOS 17.4, where the communication happens seamlessly without any new prompts. Could you please confirm if this certificate download popup behavior is expected in iOS 18? Additionally, we would appreciate any guidance on whether this change in likely to persist in future updates, as it impacts our user flow. Please let us know where we can attach video recordings of previous and current processes. Thanks
3
0
496
Nov ’24