Foundation

RSS for tag

Access essential data types, collections, and operating-system services to define the base layer of functionality for your app using Foundation.

Posts under Foundation tag

200 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

Why is fcopyfile faster than copyfile?
In my previous post I asked why copyfile is slower than the cp Terminal command. In this other post I asked how I can make copyfile faster by changing the block size. Now I discovered that the cp implementation on macOS is open source and that when copying regular files it doesn't use copyfile but fcopyfile. In a test I noticed that fcopyfile by default seems to be faster than copyfile. When copying a 7 GB file I get about the same results I observed when comparing filecopy to cp: copyfile: 4.70 s fcopyfile: 3.44 s When setting a block size of 16_777_216, copyfile becomes faster than fcopyfile: copyfile: 3.20 s fcopyfile: 3.53 s Is this expected and why is it so? I would have expected that they both have the same performance, and when changing the block size they would still have the same performance. Here is the test code. Change #if true to #if false to switch from fcopyfile to copyfile: import Foundation import System let source = "/path/to/source" let destination = "/path/to/destination" #if true let state = copyfile_state_alloc() defer { copyfile_state_free(state) } //var bsize = 16_777_216 //copyfile_state_set(state, UInt32(COPYFILE_STATE_BSIZE), &bsize) let sourceFd = try! FileDescriptor.open(source, .readOnly) let destinationFd = try! FileDescriptor.open(destination, .writeOnly) if fcopyfile(sourceFd.rawValue, destinationFd.rawValue, state, copyfile_flags_t(COPYFILE_ALL | COPYFILE_NOFOLLOW | COPYFILE_EXCL | COPYFILE_UNLINK)) != 0 { print(NSError(domain: NSPOSIXErrorDomain, code: Int(errno))) } try! sourceFd.close() try! destinationFd.close() #else source.withCString { sourcePath in destination.withCString { destinationPath in let state = copyfile_state_alloc() defer { copyfile_state_free(state) } // var bsize = 16_777_216 // copyfile_state_set(state, UInt32(COPYFILE_STATE_BSIZE), &bsize) if copyfile(sourcePath, destinationPath, state, copyfile_flags_t(COPYFILE_ALL | COPYFILE_NOFOLLOW | COPYFILE_EXCL | COPYFILE_UNLINK)) != 0 { print(NSError(domain: NSPOSIXErrorDomain, code: Int(errno))) } } } #endif
0
0
384
Jan ’24
Not able to search for local contacts with CNContactStore()
We are developing an app that uses the local contact search functionality. However, we are encountering an issue where some users are unable to search for local contacts using the contact's name or number input. Below is a code snippet from our project that uses the enumerateContacts() API from CNContactStore(): public func searchContacts(query: String, completion: @escaping SearchContactHandler) { let keysToFetch: [CNKeyDescriptor] = [ CNContactFormatter.descriptorForRequiredKeys(for: .fullName), CNContactPhoneNumbersKey as CNKeyDescriptor, ] DispatchQueue.global(qos: .userInitiated).async { [store] in do { var contacts: [PhoneContactInfo] = [] try store.enumerateContacts(with: CNContactFetchRequest(keysToFetch: keysToFetch)) { contact, _ in contacts.append(contentsOf: PhoneContactsFilter.filter(contact: contact, query: query)) } completion(.success(contacts)) } catch { completion(.failure(error)) } } } We have also tried to use the unifiedContacts() API from CNContactStore(): let storeContacts = try self.store.unifiedContacts( matching: searchNamePredicate, keysToFetch: self.keysToFetch ) var contacts: [PhoneContactInfo] = [] storeContacts.forEach { contact in contacts.append(contentsOf: PhoneContactsFilter.filter(contact: contact, query: query)) } completion(.success(contacts)) } We have considered the following factors: We always request local contact permission whenever the search is needed. searchContacts will be executed after permission is .authorized. The implementation details of PhoneContactsFilter.filter(contact: contact, query: query) can be considered correct cause it works in most of users. We tested one of the affected users and found that they were able to search for local contacts with the same code using a different app bundle ID (staging vs production). We would appreciate any insights on why some users are unable to search for local contacts with the input of the contact's name or number.
0
1
459
Jan ’24
FileManager.enumerator and URL problem
I have the following pseudo code: func load(at packageURL: URL) { let realPackageURL = packageURL.resolvingSymlinksInPath() guard let it = fileMan.enumerator(at: realPackageURL) for case let fileURL as URL in it { print(fileURL) // Get filename relative to package root directory let relativeFileName = String(filePath.suffix(filePath.count - packagePath.count)) } } When called with "file:///tmp/some.app", the enumerated fileURL is actually file:///private/tmp/GIMP.app/Contents/ packageURL.resolvingSymlinksInPath() actually does nothing, I assume /tmp is a hard link. This makes it impossible to get a correct relative path. Is there any remedy for this?
2
0
380
Jan ’24
Strange behaviour with dictionary + DateComponents keys in iOS17
A couple of unit tests for an application failed on a iOS 17.2.1 device and I could break down the problem to some strange behaviour when applying a dictionary + DateComponents keys. The tests had been running fine with iOS 16.x Here is some simplified code to reproduce the behaviour in Playground: let date1 = try! Date("2023-12-31T00:00:00Z", strategy: .iso8601) let date2 = try! Date("2024-01-31T00:00:00Z", strategy: .iso8601) let date3 = try! Date("2024-02-28T00:00:00Z", strategy: .iso8601) let date1dc = Calendar.current.dateComponents([.year, .month], from: date1) let date2dc = Calendar.current.dateComponents([.year, .month], from: date2) let date3dc = Calendar.current.dateComponents([.year, .month], from: date3) let dc1 = DateComponents(year: 2023, month: 12) let dc2 = DateComponents(year: 2024, month: 01) let dc3 = DateComponents(year: 2024, month: 02) let data: [DateComponents: String] = [ dc1: "One", dc2: "Two", dc3: "Three" ] print(date1dc == dc1) print(date2dc == dc2) print(date3dc == dc3) print("--------------------------------") print(data[dc1]) print(data[dc2]) print(data[dc3]) print("--------------------------------") print(data[date1dc]) print(data[date2dc]) print(data[date3dc]) The output for date1dc, date2dc and date3dc now is random: true true true -------------------------------- Optional("One") Optional("Two") Optional("Three") -------------------------------- Optional("One") nil Optional("Three") or true true true -------------------------------- Optional("One") Optional("Two") Optional("Three") -------------------------------- nil nil nil or true true true -------------------------------- Optional("One") Optional("Two") Optional("Three") -------------------------------- nil nil Optional("Three") For me it looks like a serious foundation bug, but maybe I'm missing something.
2
0
351
Jan ’24
Unable to upload recording of more than 15 mins to AWS server
Hi There, I am trying to record a meeting and upload it to AWS server. The recording is in .m4a format and the upload request is a URLSession request. The following code works perfectly for recordings less than 15 mins. But then for greater recordings, it gets stuck Could you please help me out in this? func startRecording() { let audioURL = getAudioURL() let audioSettings = [ AVFormatIDKey: Int(kAudioFormatMPEG4AAC), AVSampleRateKey: 12000, AVNumberOfChannelsKey: 1, AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue ] do { audioRecorder = try AVAudioRecorder(url: audioURL, settings: audioSettings) audioRecorder.delegate = self audioRecorder.record() } catch { finishRecording(success: false) } } func uploadRecordedAudio{ let _ = videoURL.startAccessingSecurityScopedResource() let input = UploadVideoInput(signedUrl: signedUrlResponse, videoUrl: videoURL, fileExtension: "m4a") self.fileExtension = "m4a" uploadService.uploadFile(videoUrl: videoURL, input: input) videoURL.stopAccessingSecurityScopedResource() } func uploadFileWithMultipart(endPoint: UploadEndpoint) { var urlRequest: URLRequest urlRequest = endPoint.urlRequest uploadTask = URLSession.shared.uploadTask(withStreamedRequest: urlRequest) uploadTask?.delegate = self uploadTask?.resume() }
3
0
484
Jan ’24
How detect cyclic symbolic links using NSFileManager?
My code is crashing Xcode (or even macOS kernel) during debugging - Xcode just vanishes from screen! // pseudo code public func hunt(in directory: URL) { let fileIterator = fileMan.enumerator(at: directory) // collect app packages into a list var packages = [URL]() for case let fileURL as URL in fileIterator { if fileURL.pathExtension == "app" { packages.append(fileURL) } } // FileWrappers var wrappers = [FileWrappers]() for packageURL in packages { //!!! The line below eventually crashes Xcode (or even macOS kernel once)! wrappers[packageURL] = try? FileWrapper(url: packageURL, options: .immediate) // NOTE: I need FileWrapper.matchesContents later in some code } } // unit test case func test() {} myObj.hunt(in: URL(fileURLWithPath: "/Applications")) } I suspect that the FileWrapper constructor is traversing directories and encounter cyclic symbolic links and eventually it crashes; since it's running at system runtime level, most probably it also crashes macOS kernel! So my question is that is there any way to detect cyclic symbolic links so that I can design my own logics similar to FileWrapper?
2
0
347
Jan ’24
IOKit with Swift
I have some Objective C code, that I can not find the equivalent for Swift (many symbols are not present). It just lists all serial devices that match a prefix: + (NSArray*)serialDevicesWithPrefix:(NSString*)prefix { NSMutableArray* modems=[NSMutableArray arrayWithCapacity:10]; kern_return_t kernResult; mach_port_t masterPort ; CFMutableDictionaryRef classesToMatch; io_iterator_t matchingServices; NSString* serialDevice=@"/dev/cu."; serialDevice=[serialDevice stringByAppendingString:prefix]; // Lets find all serial device types ; // Get the port for communications to kernal kernResult = IOMainPort(kIOMainPortDefault, &masterPort) ; if (kernResult == KERN_SUCCESS) { // We got a good result! classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue) ; if (classesToMatch != NULL) { // Now, we need to say we are looking for RS232 type of connections // Each serial device object has a property with key // kIOSerialBSDTypeKey and a value that is one of // kIOSerialBSDAllTypes, kIOSerialBSDModemType, // or kIOSerialBSDRS232Type. You can change the // matching dictionary to find other types of serial // devices by changing the last parameter in the above call // to CFDictionarySetValue. CFDictionarySetValue(classesToMatch, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDRS232Type)); kernResult = IOServiceGetMatchingServices(masterPort, classesToMatch, &matchingServices); if (kernResult == KERN_SUCCESS) { // We did something! // Matching serveres are the ones that "match" our need, now we have to loop through that and get the names io_object_t modemService; while ((modemService = IOIteratorNext(matchingServices))) { CFTypeRef deviceFilePathAsCFString; // Get the callout device's path (/dev/cu.xxxxx). // The callout device should almost always be // used. You would use the dialin device (/dev/tty.xxxxx) when // monitoring a serial port for // incoming calls, for example, a fax listener. deviceFilePathAsCFString = IORegistryEntryCreateCFProperty(modemService,CFSTR(kIOCalloutDeviceKey),kCFAllocatorDefault,0); if (deviceFilePathAsCFString) { // We got it! NSString* currentModem=(__bridge_transfer NSString *)deviceFilePathAsCFString; if ([currentModem hasPrefix:serialDevice]) { [modems addObject:currentModem]; } } IOObjectRelease(modemService) ; // We need to release it! } // We should release our iterator IOObjectRelease(matchingServices) ; } } } return modems ; } Does anyone have ideas?
2
0
542
Jan ’24
How to run code in the background on iOS? Not sure which methodology makes sense
I'm trying to set up background HTTP upload requests (syncing files from the user's phone to a server) that trigger periodically in my Swift app. I don't have strict requirements on when this runs (it can happen overnight or throughout the day). I know Apple provides several APIs for background tasks on iOS (beginBackgroundTask, BGAppRefreshTaskRequest, BGProcessingTaskRequest, URLSession upload vs. background session). And I've seen this post on the Apple developer forums that attempts to explain the differences and when to use which - as well as Apple's page on the subject, but it's still not clear to me how a few of these work in practice, and thus which ones I should utilize for my use case. My questions: How should I schedule periodic file upload tasks in the background? I assume I should use BGProcessingTaskRequest, since I don't know exactly how long the task will take (it could be syncing just 1-2 files, or it could be hundreds) and I don't care if it runs overnight How should I ensure foreground tasks are able to complete after closing the app? (i.e. when a user starts a sync manually in the app) From Apple's page on URLSessionUploadTask: "Unlike data tasks, you can use upload tasks to upload content in the background." Does this mean any requests I make using URLSession.shared.upload() will automatically run in the background if the user closes the app? Even with the async/await version, or do I have to use the completionHandler version? Do I need to call beginBackgroundTask if I'm using URLSession.shared.upload() to guarantee I get more time to finish uploads? What about sequential requests (i.e. requests that haven't started yet by the time the app is closed)? Based on this StackOverflow response, it sounds like I may need to trigger all the uploads in parallel beforehand? https://stackoverflow.com/a/53949607/2359478 Should I even consider URLSessionConfiguration.background for my use case? It sounds like it I use beginBackgroundTask and BGProcessingTaskRequest then this may be unnecessary? Thanks!
3
1
1.7k
Jan ’24
/usr/bin/log sometimes does not work through NSTask
Our application (which happens to run in an admin account, thus there's no problem authenticating) collects logs calling /usr/bin/log through NSTask. Usually this works all right, but sometimes all we get is the header Timestamp Thread Type Activity PID TTL and nothing else. The tool finishes with a zero result code, we get nothing on stderr and just the header above on stdout, with a proper EOF (as determined by a zero-length availableData read from an NSFileHandle through the stdout pipe). At the same moment, if the /usr/bin/log tool is run manually in a Terminal window with precisely the same arguments in the same user account the application runs in, we get the logs all right. Any idea what might be the culprit and how to fix the problem? Thanks!
0
0
489
Jan ’24
Making filecopy faster by changing block size
I'm using the filecopy function to copy many files and I noticed that it always takes longer than similar tools like cp or a Finder copy (I already did a comparison in my other post). What I didn't know before was that I can set the block size which apparently can have a big influence on how fast the file copy operation is. The question now is: what should I consider before manually setting the block size? Does it make sense to have a block size that is not a power of 2? Can certain block sizes cause an error, such as a value that is too large (for the Mac the code is running on, or for the source and target devices)? When should or shouldn't I deviate from the default? Is there a way to find out the optimal block size for given source and target devices, or at least one that performs better than the default? In the following sample code I tried to measure the average time for varying block sizes, but I'm not sure it's the best way to measure it, since each loop iteration can have wildly different durations. class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ aNotification: Notification) { let openPanel = NSOpenPanel() openPanel.runModal() let source = openPanel.urls[0] openPanel.canChooseDirectories = true openPanel.canChooseFiles = false openPanel.runModal() let destination = openPanel.urls[0].appendingPathComponent(source.lastPathComponent) let date = Date() let count = 10 for _ in 0..<count { try? FileManager.default.removeItem(at: destination) do { try copy(source: source, destination: destination) } catch { preconditionFailure(error.localizedDescription) } } print(-date.timeIntervalSinceNow / Double(count)) } func copy(source: URL, destination: URL) throws { try source.withUnsafeFileSystemRepresentation { sourcePath in try destination.withUnsafeFileSystemRepresentation { destinationPath in let state = copyfile_state_alloc() defer { copyfile_state_free(state) } // var bsize = Int32(16_777_216) var bsize = Int32(1_048_576) if copyfile_state_set(state, UInt32(COPYFILE_STATE_BSIZE), &bsize) != 0 || copyfile_state_set(state, UInt32(COPYFILE_STATE_STATUS_CB), unsafeBitCast(copyfileCallback, to: UnsafeRawPointer.self)) != 0 || copyfile_state_set(state, UInt32(COPYFILE_STATE_STATUS_CTX), unsafeBitCast(self, to: UnsafeRawPointer.self)) != 0 || copyfile(sourcePath, destinationPath, state, copyfile_flags_t(COPYFILE_ALL | COPYFILE_NOFOLLOW | COPYFILE_EXCL)) != 0 { throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno)) } } } } private let copyfileCallback: copyfile_callback_t = { what, stage, state, src, dst, ctx in if what == COPYFILE_COPY_DATA { if stage == COPYFILE_ERR { return COPYFILE_QUIT } var size: off_t = 0 copyfile_state_get(state, UInt32(COPYFILE_STATE_COPIED), &size) let appDelegate = unsafeBitCast(ctx, to: AppDelegate.self) if !appDelegate.setCopyFileProgress(Int64(size)) { return COPYFILE_QUIT } } return COPYFILE_CONTINUE } private func setCopyFileProgress(_ progress: Int64) -> Bool { return true } }
14
1
890
Jan ’24
depreciated methods
Im trying to create a function to retrieve my Mac's RAM usage but I get alerts saying essentially that my 'scanDouble' and 'scanCharecters(from:into:)' methods have been depreciated and Xcode also throw me these alerts if I compile this code. what are the newer alternatives to these methods? import Foundation class RAMUsage { let processInfo = ProcessInfo.processInfo func getRAM() { let physicalMemory = processInfo.physicalMemory let formatter = ByteCountFormatter() formatter.countStyle = .memory let formattedMemoryUsage = formatter.string(fromByteCount: Int64(physicalMemory)) parseAndPrint(formattedMemoryUsage: formattedMemoryUsage) } func parseAndPrint(formattedMemoryUsage: String) { print("Formatted RAM usage: \(formattedMemoryUsage)") if let gigsOfRAM = parseFormattedRAMUsage(formattedUsage: formattedMemoryUsage) { print("RAM Usage in Gigabytes: \(gigsOfRAM) GB") } else { print("Could not retrieve or parse RAM usage") } } func parseFormattedRAMUsage(formattedUsage: String) -> Double? { let scanner = Scanner(string: formattedUsage) var value: Double = 0.0 var unit: NSString? if scanner.scanDouble(&value) { scanner.scanCharacters(from: .letters, into: &unit) if let unitString = unit as String?, unitString.lowercased() == "GB" { print("Parsed RAM Usage: \(value) GB") return value } else { print("could not parse and return value") } } return nil } }
7
0
688
Dec ’23
HTTPURLResponse Response is Incomplete
Hello, I am having an issue with my request response only containing a partial response body despite the request having a 200 http response status. When I print out the raw response without parsing it to JSON I can see that the content is truncated (leading to an invalid JSON). I am unable to reproduce the same issue on Postman, so this seems to be isolated to my ios app (I have had the same issue with the endpoint in React Native as well). Any tips or suggestions would be appreciated! (Excuse the code, learning swift as I go) class Fetcher<T, G>: ObservableObject where T: Decodable, G: Codable { @Published var data: T? = nil @Published var isLoading: Bool = false public var path: [String] { return [] } func fetchData(body: G) async throws { Task { @MainActor in isLoading = true } var url = NetworkManager.shared.baseUrl; for p in path { url = url.appending(path: p) } var request = URLRequest(url: url) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.httpBody = try? JSONEncoder().encode(body) // TODO: This should be handled with auth challenges if let token = NetworkManager.shared.token { request.setValue(token, forHTTPHeaderField: "Authorization"); } // Set timezone header request.setValue(TimeZone.current.identifier, forHTTPHeaderField: "TIMEZONE"); let (respData, response) = try await NetworkManager.shared.session.data(for: request) let json = String(data: respData, encoding: String.Encoding.utf8) if let token = (response as? HTTPURLResponse)?.value(forHTTPHeaderField: "Authorization") { NetworkManager.shared.token = token } guard (response as? HTTPURLResponse)?.statusCode == 200 else { Task { @MainActor in isLoading = false } throw FetchError.badRequest } let temp = try JSONDecoder().decode(T.self, from: respData) Task { @MainActor in data = temp isLoading = false } } } class NetworkManager{ static let shared = NetworkManager(baseUrl: "https://my-api-url.com"); let baseUrl: URL let session: URLSession var token: String? private init(baseUrl: String) { // TODO: Throw well defined error self.baseUrl = URL(string: baseUrl)! let configuration = URLSessionConfiguration.default self.session = URLSession(configuration: configuration) } }
2
1
570
Dec ’23
NSKeyedArchiver error after cleaned a mistake
I tried to archive a NSDictionary with a NSColor : data = [NSKeyedArchiver archivedDataWithRootObject: <vrRoot> requiringSecureCoding:YES error:&error]; and I get this error : Printing description of error: Error Domain=NSCocoaErrorDomain Code=4864 "value for key 'NS.objects' was of unexpected class 'NSColor' (0x7ff8465d0d88) [/System/Library/Frameworks/AppKit.framework]. Allowed classes are: {( "'NSMutableDictionary' (0x7ff8465f9b48) [/System/Library/Frameworks/CoreFoundation.framework]" )}" UserInfo={NSDebugDescription=value for key 'NS.objects' was of unexpected class 'NSColor' (0x7ff8465d0d88) [/System/Library/Frameworks/AppKit.framework]. Allowed classes are: {( "'NSMutableDictionary' (0x7ff8465f9b48) [/System/Library/Frameworks/CoreFoundation.framework]" )}} Then I transferred NSColor to NSArray - but the error was the same. I want data save in Core Data, please help me ♡.
1
0
537
Jan ’24
JsonEncode crashes
the following code produces this crash for about 0.5% of the users : guard let encodedData = try? jsonEncoder.encode(project) else { throw AutoCapError.encodeVideoProject } Crashed: com.apple.root.background-qos 0 libswiftCore.dylib 0x20e468 StringObject.getSharedUTF8Start() + 8 1 libswiftCore.dylib 0x20e498 StringObject.sharedUTF8.getter + 24 2 Foundation 0x259698 specialized String.withUTF8(:) + 1348 3 Foundation 0x25986c JSONWriter.serializeString(:) + 100 4 Foundation 0x44648 JSONWriter.serializeJSON(:depth:) + 92 5 Foundation 0x44d68 JSONWriter.serializeObject(:depth:) + 1344 6 Foundation 0x4474c JSONWriter.serializeJSON(:depth:) + 352 7 Foundation 0x44d68 JSONWriter.serializeObject(:depth:) + 1344 8 Foundation 0x460a8 JSONWriter.serializeArray(:depth:) + 892 9 Foundation 0x44718 JSONWriter.serializeJSON(:depth:) + 300 10 Foundation 0x44d68 JSONWriter.serializeObject(:depth:) + 1344 11 Foundation 0x460a8 JSONWriter.serializeArray(:depth:) + 892 12 Foundation 0x44718 JSONWriter.serializeJSON(:depth:) + 300 13 Foundation 0x44d68 JSONWriter.serializeObject(:depth:) + 1344 14 Foundation 0x4474c JSONWriter.serializeJSON(:depth:) + 352 15 Foundation 0x43ce8 JSONEncoder.encode(:value:) + 608 16 Foundation 0x43a7c JSONEncoder.encode(:) + 64 17 Foundation 0x43a34 dispatch thunk of JSONEncoder.encode(_:) + 56 the crash started since the iOS 17 (worked before) the project Object is has many String fields and it mostly crashes on none english languages, Why isn't the try catches the crash? what might be causing it? fool crash report is attached laika.autocap_issue_b2c4b37d2bb22ddab10152c2bb743fbc_crash_session_cb8d05d0956f4bf38de34d313bb64067_DNE_0_v2_stacktrace.txt
3
0
721
Jan ’24
Calendar nextDate/enumerateDates methods with backward direction does not work for September
I’m trying to get the previous date that matches the 9nth month in the Gregorian calendar (which is September) from Date.now (which is in December 2023 right now). The expected date is then in 2023. The first date returned is in 1995. Why? I filed the feedback FB13462533 var calendar: Calendar = Calendar(identifier: .gregorian) calendar.timeZone = TimeZone.autoupdatingCurrent let matchingDateComponents: DateComponents = DateComponents(month: 09) let date: Date? = calendar.nextDate( after: Date.now, matching: matchingDateComponents, matchingPolicy: .nextTime, direction: .backward ) print(date) // Optional(1995-08-31 23:00:00 +0000)
4
0
452
Dec ’23