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
Foundation
RSS for tagAccess 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
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.
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?
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.
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()
}
Does anyone have the format string to use to just get the 24 hour time (no am/pm) indicator from Date?
I can't seem to get 24 hour time with:
let now = Date()
now.formatted(date:.omitted,time:.complete) // Or any of the time options.
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?
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?
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!
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!
Is it possible to programmatically access and manipulate the native text replacements of macOS? If so, what are the APIs or methods to achieve this, considering the sandboxing and privacy restrictions in the latest versions of macOS?
iOS17 NSURLSession errors when downloading Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory
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
}
}
print(String(format: "%.2f", 1.255)) => 1.25
print(String(format: "%.2f", 1.256)) => 1.26
It's not rounded ?? Or am I missing something ??
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
}
}
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)
}
}
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 ♡.
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
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)
I vaguely remember I came across some classes about file packages. Just cannot recall the exact names. Can anyone help?