Post

Replies

Boosts

Views

Activity

startAccessingSecurityScopedResource always returns false for files in iCloud Drive folder
Hello, I am trying to use the SwiftUI fileImporter to get the URL of a direcotry and access it for the files in it. If I follow the document( Access the directory’s content ) and use url.startAccessingSecurityScopedResource for each file, it always returns false. but this seems to be different from the documentation. If the current behavior is correct, will the documentation be updated in the future? Related: Access all files in UIDocumentPick… | Apple Developer Forums I asked this question because I am concerned that if I remove the standardAccessingSecurityScopedResource to match the current situation, the standardAccessingSecurityScopedResource may become necessary due to future iOS updates. Also, is there any way to know if the status of the AccessingSecurityScopedResource? It would be helpful if we could callstartAcesingSecurityScopedResource only when needed. Thanks Here is a sample code @main struct SampleApp: App { var body: some Scene { WindowGroup { ContentView() } } } struct ContentView: View { @State private var isShowingImportFolder = false @State private var isShowingImportFile = false var body: some View { VStack(spacing: 48) { Button("Read Folder") { isShowingImportFolder = true } .fileImporter(isPresented: $isShowingImportFolder, allowedContentTypes: [.folder]) { result in switch result { case .success(let url): processDirectory(url) case .failure(let error): print("failed. error: \(error)") } } Button("Read File") { isShowingImportFile = true } .fileImporter(isPresented: $isShowingImportFile, allowedContentTypes: [.data]) { result in switch result { case .success(let url): readFile(url) case .failure(let error): print("failed. error: \(error)") } } } } private func processDirectory(_ directory: URL) { guard directory.startAccessingSecurityScopedResource() else { fatalError("failed. directory.startAccessingSecurityScopedResource") } defer { directory.stopAccessingSecurityScopedResource() } var error: NSError? NSFileCoordinator().coordinate(readingItemAt: directory, error: &error) { url in let urls = try! FileManager.default.contentsOfDirectory(at: url, includingPropertiesForKeys: [.nameKey, .isDirectoryKey]) urls.lazy .filter { !$0.hasDirectoryPath } .forEach { readFile($0) } } } private func readFile(_ url: URL) { guard url.startAccessingSecurityScopedResource() else { print("failed access. \(url.path)") return } defer { url.stopAccessingSecurityScopedResource() } let data = try! Data(contentsOf: url) print("file.path: \(url.path()), size: \(data.count)") // read file... } }
1
0
1.6k
Mar ’24
Is ObservableObject implicitly a MainActor in iOS 16 and later?
This is a question regarding the specification of ObservalObject. The following code does not cause a compilation error when the deployment target is set to iOS 16, but it does cause the following error when set to iOS 15: class Model: ObservableObject { let player: AVPlayer @Published var isPlaying = false var playerObserver: NSKeyValueObservation? init() { self.player = AVPlayer() self.playerObserver = self.player.observe(\.rate, options: [.new, .old]) { player, change in NSLog("changed rate: \(String(describing: change.newValue))") } } func setup() { let name = "sample" let url = Bundle.main.url(forResource: name, withExtension: "m4a")! let playerItem = AVPlayerItem(url: url) self.player.replaceCurrentItem(with: playerItem) } func play() { self.player.play() self.isPlaying = true } } The following error occurs in iOS 15: Cannot form key path to main actor-isolated property 'rate' Call to main actor-isolated instance method 'play()' in a synchronous nonisolated context Additionally, if the code is modified as follows, the error does not occur even in iOS 15. Specifically, adding @MainActor to the Model resolves the issue. @MainActor class Model: ObservableObject { ... } From this behavior, I guessed that ObservableObject is implicitly a MainActor in iOS 16 and later. Is this understanding correct?
1
0
618
Jul ’24
List Layout Breaks in NavigationStack When a View Exceeds Screen Width
This is a bug report. FB17433985 The layout of the following ContentView appears correctly when it is outside a NavigationStack. However, when the same view is placed inside a NavigationStack, the layout breaks. It seems that the width of the List is being affected by the width of the buttonsView, which exceeds the screen width. In my testing, this issue occurs on iOS 18.4 and later, but does not occur on iOS 18.2 or iOS 17.5. Workaround I found: Remove the fixed width modifier from the Button If anyone knows of other ways to resolve this issue without affecting the layout, I would appreciate it if you could share them. import SwiftUI let values = (1...100).map { $0 } let buttonTitles = (1...9).map { "Button\($0)" } struct ContentView: View { var body: some View { VStack { List { Section { ForEach(values.indices, id: \.self) { val in HStack { Text("Index: \(val)") } } } } buttonsView } } private var buttonsView: some View { HStack { ForEach(0..<buttonTitles.count, id: \.self) { index in Button() { } label: { Image(systemName: "square.and.arrow.up") .resizable() .frame(width: 48, height: 48) } } } } } @main struct ButtonShapeBugApp: App { var body: some Scene { WindowGroup { if true { NavigationStack { ContentView() } } else { ContentView() } } } } Environment: Xcode Version 16.3 (16E140) iPhone 18.4.1 real device iPhone SE3rd 18.4 simulator Expect layout Broken layout(9 buttons) Broken layout(10 buttons)
2
0
79
May ’25
.highPriorityGesture Prevents Button Tap on iOS 17 and Earlier
In iOS 18, using .highPriorityGesture does not interfere with Button tap detection. However, on iOS 17 and earlier, setting a .highPriorityGesture causes the Button's tap action to stop responding. I am using .highPriorityGesture in an attempt to support both tap and long-press gestures on a Button, which works as expected in iOS 18. However, the same implementation prevents taps on earlier versions. Is using .highPriorityGesture on a Button not recommended in this case? Or is this an issue specific to how .highPriorityGesture behaves on iOS 17 and earlier? Below is a sample code: struct SampleButton: View { let title: String let action: () -> Void var body: some View { Button { NSLog("Tapped") action() } label: { Text(title) }.highPriorityGesture(LongPressGesture(minimumDuration: 0.5).onEnded { _ in NSLog("Long press.") action() }) } } struct ContentView: View { var body: some View { VStack { SampleButton(title: "Tap or LongPress") {} } } } Environment: Xcode: Version 16.3 (16E140) iOS: iOS 18.4(simulator), iOS 17.5, iOS 16.4, iOS 15.2
3
0
107
May ’25
StateObject is not deinitialized when List(selection:) binding
Hello, I have a simple example using StateObject and List. When I bind the List(selection:) to a property of the StateObject like this: List(selection: $viewModel.selectedIndex) { ... } I noticed that each time I push the view using a NavigationLink, a new instance of the StateObject is created. However, when I pop the view, the deinit of the StateObject is not called. When is deinit actually expected to be called in this case? Example code: import SwiftUI @main struct NavigationViewDeinitSampleApp: App { var body: some Scene { WindowGroup { NavigationStack { ContentView() } } } } struct Item: Hashable { let text: String } @MainActor fileprivate class ContentViewModel: ObservableObject { @Published var selectedIndex: Int? = nil init() { NSLog("ContentViewModel.init") } deinit { NSLog("ContentViewModel.deinit") } } struct ContentView: View { @StateObject private var model = ContentViewModel() let items: [Item] = { return (0...10).map { i in Item(text: "\(i)") } }() var body: some View { List(selection: $model.selectedIndex) { ForEach(items.indices, id: \.self) { idx in let item = items[idx] NavigationLink { ContentView() } label: { Text(item.text) } } } } } Interestingly, if I instead use a plain @State variable inside the View: @State private var selectedIndex: Int? ... List(selection: $selectedIndex) { ... } Then the deinit of the StateObject does get called when the view is popped. Because there's no sign of deinit being triggered in the first pattern, I’m starting to suspect this might be a SwiftUI bug. Has anyone seen this behavior or have more information about it? Thanks in advance. Environment: Xcode: 16.4(16F6) iOS Simulator: iPhone SE3 iOS16.4(20E247),iPhone SE3 iOS 18.4(22E238)
1
0
137
Jul ’25