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.

Pinned Posts

Posts under Foundation tag

341 Posts
Sort by:
Post not yet marked as solved
7 Replies
7.7k Views
Using the new date formatting API available in iOS 15, I would like to respect the 12 vs 24 hour setting on a user-by-user basis. With DateFormatter it can be done as follows, for example, to force a 24 hour time irrespective of the user locale. let formatter = DateFormatter() formatter.dateFormat = "HH:mm" // or hh:mm for 12 h However, I cannot figure out how to force the new date formatting API in iOS 15 to do the same thing, i.e. force displaying 12 vs 24 h. I'm using a format style like this: var formatStyle = dateTime formatStyle.calendar = calendar if let timeZone = timeZone { formatStyle.timeZone = timeZone } return formatStyle And applying it like this, for example, for a given Date instance: date.formatted(formatStyle.hour(.defaultDigits(amPM: .abbreviated))) However, this seems to always give a formatted string relevant to the locale, for example, it's always 12h for the US and always 24h for the UK. This is not the behaviour I really need though, and I'd like to allow each individual user to control what they see irrespective of the locale setting. (Note that there is an in-app setting that allows the user to toggle between the 12 and 24 hour preference, which is the value I'd like to use to set the preference.)
Posted
by
Post not yet marked as solved
6 Replies
3.3k Views
We have been seeing a NSURLError cannot parse error with error code -1017 for 0.01% of all the requests fired from our native app. We double checked the request headers and cookies but found no difference from the API calls that succeeded for the same path. For most of these requests, we found (through our analytics tools) that 99% of the times, there was no response received from the server(response object is nil); trying to understand why would a no response cause a cannot parse error. We do not get much information from error received as to what really went wrong, did the request even reach the server or was killed or modified by the OS? Any help or further detail will be very helpful. Error in detail: Foundation.URLError(_nsError: Error Domain=NSURLErrorDomain Code=-1017 "cannot parse response" UserInfo={NSUnderlyingError=0x280eddc50 {Error Domain=kCFErrorDomainCFNetwork Code=-1017 "(null)" UserInfo={_kCFStreamErrorCodeKey=-1, _kCFStreamErrorDomainKey=4}}, NSErrorFailingURLStringKey=https://mydomain.com/path, NSErrorFailingURLKey=https://mydomain.com/path, _kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-1, NSLocalizedDescription=cannot parse response})
Posted
by
Post marked as solved
9 Replies
1.4k Views
Attached is an entire project (4 files) that mirrors my actual project including the failure to save to file. Am I: missing some syntax in this code? failing to config a defaults file? not set the necessary parameters in " "Build Settings" or "Build Rules etc.? I was writing to JSON files, but now that I must append to files directly, and JSON doesn't do that easily, I am trying to write using native macOS tools. WELL, IT SEEMS I CAN'T SEND YOU THE CODE, TOO MANY CHARS. I CAN'T ATTACH ANY FILE EITHER. WHY OFFER IT IF IT IS NOT ALLOWED? ANYWAY, CAN YOU GLEAN ANYTHING FROM THIS... Thanks. My debugger area: 2022-05-28 12:03:11.827372-0500 exampleClassInClassSecureCoding[1508:29981] Metal API Validation Enabled 2022-05-28 12:03:11.940123-0500 exampleClassInClassSecureCoding[1508:29981] *** NSForwarding: warning: object 0x600003cf7090 of class 'exampleClassInClassSecureCoding.classOne' does not implement methodSignatureForSelector: -- trouble ahead Unrecognized selector -[exampleClassInClassSecureCoding.classOne replacementObjectForKeyedArchiver:] 2022-05-28 12:03:11.940416-0500 exampleClassInClassSecureCoding[1508:29981] Unrecognized selector -[exampleClassInClassSecureCoding.classOne replacementObjectForKeyedArchiver:] Unrecognized selector -[exampleClassInClassSecureCoding.classOne replacementObjectForKeyedArchiver:] Performing @selector(didPressButton:) from sender _TtC7SwiftUIP33_9FEBA96B0BC70E1682E82D239F242E7319SwiftUIAppKitButton 0x7ff08ab06480
Posted
by
Post not yet marked as solved
0 Replies
2k Views
General: TN3151 Choosing the right networking API Networking Overview document — Despite the fact that this is in the archive, this is still really useful. TLS for App Developers DevForums post Choosing a Network Debugging Tool documentation WWDC 2019 Session 712 Advances in Networking, Part 1 — This explains the concept of constrained networking, which is Apple’s preferred solution to questions like How do I check whether I’m on Wi-Fi? TN3135 Low-level networking on watchOS Adapt to changing network conditions tech talk Foundation networking: DevForums tags: Foundation, CFNetwork URL Loading System documentation — NSURLSession, or URLSession in Swift, is the recommended API for HTTP[S] on Apple platforms. Network framework: DevForums tag: Network Network framework documentation — Network framework is the recommended API for TCP, UDP, and QUIC on Apple platforms. Network Extension (including Wi-Fi on iOS): See Network Extension Resources Wi-Fi Fundamentals Wi-Fi on macOS: DevForums tag: Core WLAN Core WLAN framework documentation Wi-Fi Fundamentals Secure networking: DevForums tags: Security Apple Platform Security support document Preventing Insecure Network Connections documentation — This is all about App Transport Security (ATS). Available trusted root certificates for Apple operating systems support article Requirements for trusted certificates in iOS 13 and macOS 10.15 support article About upcoming limits on trusted certificates support article Apple’s Certificate Transparency policy support article Technote 2232 HTTPS Server Trust Evaluation Technote 2326 Creating Certificates for TLS Testing QA1948 HTTPS and Test Servers Miscellaneous: More network-related DevForums tags: 5G, QUIC, Bonjour On FTP DevForums post Using the Multicast Networking Additional Capability DevForums post Investigating Network Latency Problems DevForums post Local Network Privacy FAQ DevForums post Extra-ordinary Networking DevForums post Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com"
Posted
by
Post marked as solved
3 Replies
1.7k Views
Our (legacy) code to communicate with peripherals on local IPv6 networks (LAN) adds the zone identifier / interface name ("%en0") to link-local IP addresses (FE80::/10) discovered via SSDP. SSDP is implemented using CocoaAsyncSocket - yes, that part of our code is old... (from before the introduction of the iOS 12+ Network framework). We use these modified IP addresses as the host component of a URL in a URLSession.dataTask. To insert the zone identifier we are using URLComponents (we modify the host and then request the string). This worked fine in iOS 15 and below, but no longer works in iOS 16 (Beta 1/2/3); the host is empty after inserting %en0 in the most recent beta. We have reported this via FB10549269, but from the answer it is unclear to me whether Apple is planning to fix this ("Resolution: Potential fix identified"), or we are doing it wrong. How should we handle IPv6 link-local addresses in iOS 16? (when using URLSession instead of Network) PS: We recently dropped support for iOS 12, but we still need to support iOS 13 and up
Posted
by
Post marked as solved
7 Replies
3.7k Views
In iOS 16 beta 3, my iOS app sets some strings in the shared user defaults of the app group. The iOS widget extension reads the strings from the shared user defaults correctly, but the watchOS app and watchOS widget extension could not read them (get nil). Integers stored in the shared user defaults can be read everywhere. All targets are in the same app group. Does anyone have similar problems?
Posted
by
Post marked as solved
2 Replies
2.2k Views
We've enabled ATS restrictions in our app, and everything works fine, except sometimes, randomly, the CDN download resource fails. In most cases, it happens to users who on iOS 14.* and WiFI (VPN helps solve the problem :thinking_face:) Logs: (ExampleClientErrorLogServlet) :: Client error: {"arguments":["test_resource","Caught Error Domain%3DNSURLErrorDomain Code%3D-1200 \"An SSL error has occurred and a secure connection to the server cannot be made.\" UserInfo%3D{NSErrorFailingURLStringKey%3Dhttps://my-url/reource.bin, NSLocalizedRecoverySuggestion%3DWould you like to connect to the server anyway?, _kCFStreamErrorDomainKey%3D3, _NSURLErrorFailingURLSessionTaskErrorKey%3DLocalDownloadTask <A50DCF0E-38F3-4454-A78A-B4552336561E>.<1>, _NSURLErrorRelatedURLSessionTaskErrorKey%3D(\n \"LocalDownloadTask <A50DCF0E-38F3-4454-A78A-B4552336561E>.<1>\"\n), NSLocalizedDescription%3DAn SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey%3Dhttps://my-url/reource.bin, NSUnderlyingError%3D0x2882e1050 {Error Domain%3DkCFErrorDomainCFNetwork Code%3D-1200 \"(null)\" UserInfo%3D{_kCFStreamPropertySSLClientCertificateState%3D0, _kCFNetworkCFStreamSSLErrorOriginalValue%3D-9816, _kCFStreamErrorDomainKey%3D3, _kCFStreamErrorCodeKey%3D-9816, _NSURLErrorNWPathKey%3Dsatisfied (Path is satisfied), viable, interface: en0, ipv4, dns}}, _kCFStreamErrorCodeKey%3D-9816}"],"format":"Downloading {} file failed: {}","platform":"ios","version":"2.87.1"} 26.07.2022 01:39:55 [DEBUG][9] :: platform: ios, version: 2.87.1. Downloading test_resource file failed: Caught Error Domain%3DNSURLErrorDomain Code%3D-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo%3D{NSErrorFailingURLStringKey%3Dhttps://my-url/reource.bin, NSLocalizedRecoverySuggestion%3DWould you like to connect to the server anyway?, _kCFStreamErrorDomainKey%3D3, _NSURLErrorFailingURLSessionTaskErrorKey%3DLocalDownloadTask <A50DCF0E-38F3-4454-A78A-B4552336561E>.<1>, _NSURLErrorRelatedURLSessionTaskErrorKey%3D( ), NSLocalizedDescription%3DAn SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey%3Dhttps://my-url/reource.bin, NSUnderlyingError%3D0x2882e1050 {Error Domain%3DkCFErrorDomainCFNetwork Code%3D-1200 "(null)" UserInfo%3D{_kCFStreamPropertySSLClientCertificateState%3D0, _kCFNetworkCFStreamSSLErrorOriginalValue%3D-9816, _kCFStreamErrorDomainKey%3D3, _kCFStreamErrorCodeKey%3D-9816, _NSURLErrorNWPathKey%3Dsatisfied (Path is satisfied), viable, interface: en0, ipv4, dns}}, _kCFStreamErrorCodeKey%3D-9816} _kCFNetworkCFStreamSSLErrorOriginalValue=-9816 _kCFStreamErrorDomainKey=3 _kCFStreamErrorCodeKey=-9816 We've tried nscurl --ats-diagnostics on the URL: Configuring ATS Info.plist keys and displaying the result of HTTPS loads to https:/url-path. A test will "PASS" if URLSession:task:didCompleteWithError: returns a nil error. ============================================================== Default ATS Secure Connection --- ATS Default Connection ATS Dictionary: {} Result : PASS --- ============================================================== Allowing Arbitrary Loads --- Allow All Loads ATS Dictionary: {     NSAllowsArbitraryLoads = true; } Result : PASS --- ================================================================================ Configuring TLS exceptions for url --- TLSv1.3 ATS Dictionary: {     NSExceptionDomains =     {         "url" =         {             NSExceptionMinimumTLSVersion = "TLSv1.3";         };     }; } Result : FAIL Error : Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSErrorFailingURLStringKey=url, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <250D7C7A-A090-41F1-8FED-E73FCB511F41>.<1>, _NSURLErrorRelatedURLSessionTaskErrorKey=(     "LocalDataTask <250D7C7A-A090-41F1-8FED-E73FCB511F41>.<1>" ), NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey=url, NSUnderlyingError=0x6000021318f0 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, _kCFNetworkCFStreamSSLErrorOriginalValue=-9836, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9836, _NSURLErrorNWPathKey=satisfied (Path is satisfied), viable, interface: lo0}}, _kCFStreamErrorCodeKey=-9836} --- ====================================== nsurl --ats-diagnostic show me another error code -9836 and like I know TLSv1.3 not necessary yet Maybe someone can give some suggestions, any help !! :pray: Thx!
Posted
by
Post not yet marked as solved
4 Replies
1.5k Views
iOS 16 introduced "Internationalized Domain Name" support for URLComponent. As a result, URLComponent does not accept IPv6 address as host in iOS 16. Is this expected behaviour or a bug, and what would be the best workaround in this case? // IPv4 URL var ipv4URLComponents = URLComponents() ipv4URLComponents.scheme = "https" ipv4URLComponents.host = "66.94.29.13" if let url = ipv4URLComponents.url {     print("IPv4 URL:", url) } // IPv6 URL var ipv6URLComponents = URLComponents() ipv6URLComponents.scheme = "https" ipv6URLComponents.host = "2001:0000:3238:dfe1:0063:0000:0000:fefb" if let url = ipv6URLComponents.url {     print("IPv6 URL:", url) } Output on iOS 15.5 device: IPv4 URL: https://66.94.29.13 IPv6 URL: https://2001%3A0000%3A3238%3Adfe1%3A0063%3A0000%3A0000%3Afefb Output on iOS 16 device: IPv4 URL: https://66.94.29.13 IPv6 URL: https: Related thread: https://developer.apple.com/forums/thread/709284
Posted
by
Post not yet marked as solved
11 Replies
2.3k Views
There are many crashes at iOS16 in CFURLRequestSetURL. The crash log Crashed: com.apple.NSURLSession-work 0 CFNetwork 0x18578 CFURLRequestSetURL + 14416 1 libdispatch.dylib 0x24b4 _dispatch_call_block_and_release + 32 2 libdispatch.dylib 0x3fdc _dispatch_client_callout + 20 3 libdispatch.dylib 0xb694 _dispatch_lane_serial_drain + 672 4 libdispatch.dylib 0xc214 _dispatch_lane_invoke + 436 5 libdispatch.dylib 0x16e10 _dispatch_workloop_worker_thread + 652 6 libsystem_pthread.dylib 0xdf8 _pthread_wqthread + 288 7 libsystem_pthread.dylib 0xb98 start_wqthread + 8
Posted
by
Post not yet marked as solved
2 Replies
982 Views
When a file named a.txt is not downloaded locally, the iCloud Drive folder actually only contains a placeholder named .a.txt.icloud (that is still displayed as a.txt by the Finder) with a very small file size, something like 176 bytes. How can I get the original file size, like the Finder displays?
Posted
by
Post not yet marked as solved
5 Replies
1.7k Views
Is there any way to read/write preferences for a Mac app group using the defaults command? I'm talking about the stuff you would programmatically manipulate using [NSUserDefaults initWithSuiteName:], and that is stored on disk in ~/Library/Group Containers. If I just say defaults read <suite name>, it tells me the the domain does not exist.
Posted
by
Post not yet marked as solved
3 Replies
1.3k Views
I have an app which uses URLSession-based networking and URLCache for storing network requests on disk. I noticed that when the storage size of URLCache reaches the diskCapacity, the eviction strategy seems to be to remove all entries, which is a problem in my use case. So I decided to write an URLCache subclass which would provide a custom storage for cached responses and which would implement LRU eviction strategy with better control. As URLCache's documentation states, subclassing for this purpose should be supported: The URLCache class is meant to be used as-is, but you can subclass it when you have specific needs. For example, you might want to screen which responses are cached, or reimplement the storage mechanism for security or other reasons. However, I ran into problems with trying to use this new URLCache subclass with URLSession networking. I have a test resource which I fetch using HTTP GET. The response headers contain: Cache-Control: public, max-age=30 Etag: <some-value> When using the standard, non-subclassed URLCache, the first request loads the data from network as expected (verified with HTTP proxy). The second request doesn't go to the network, if done within first 30 seconds, as expected. Subsequent requests after 30 seconds cause conditional GETs with Etag, as expected. When using a URLCache subclass, all requests load the data from network - max-age doesn't seem to matter, and no conditional GETs are made. It seems that the URLCache does something special to the CachedURLResponse instances after they're loaded from its internal storage, and this something affects how URLSession handles the HTTP caching logic. What am I missing here? I've written a very minimal URLCache implementation to demonstrate this problem. This class stores and loads CachedURLResponse instances using NSKeyedArchiver / NSKeyedUnarchiver, and it supports only zero or one response. Note that there are no calls to super - this is by design, since I want to use my own storage. Here's the implementation: class CustomURLCache: URLCache { let cachedResponseFileURL = URL(filePath: NSTemporaryDirectory().appending("entry.data")) // MARK: Internal storage func read() -> CachedURLResponse? { guard let data = try? Data(contentsOf: cachedResponseFileURL) else { return nil } return try! NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as! CachedURLResponse } func store(_ cachedResponse: CachedURLResponse) { try! (try! NSKeyedArchiver.archivedData(withRootObject: cachedResponse, requiringSecureCoding: false)).write(to: cachedResponseFileURL) } // MARK: URLCache Overrides override func cachedResponse(for request: URLRequest) -> CachedURLResponse? { read() } override func getCachedResponse(for dataTask: URLSessionDataTask, completionHandler: @escaping (CachedURLResponse?) -> Void) { guard let response = read() else { completionHandler(nil) return } completionHandler(response) } override func storeCachedResponse(_ cachedResponse: CachedURLResponse, for request: URLRequest) { store(cachedResponse) } override func storeCachedResponse(_ cachedResponse: CachedURLResponse, for dataTask: URLSessionDataTask) { store(cachedResponse) } } My test case: func test() { let useEvictingCache = false let config = URLSessionConfiguration.default if useEvictingCache { config.urlCache = CustomURLCache() } else { config.urlCache = URLCache(memoryCapacity: 0, diskCapacity: 1024 * 1024 * 100) } self.urlSession = URLSession(configuration: config) let url = URL(string: "https://example.com/my-test-resource")! self.urlSession?.dataTask(with: URLRequest(url: url), completionHandler: { data, response, error in if let data { print("GOT DATA with \(data.count) bytes") } else if let error { print("GOT ERROR \(error)") } }).resume() }
Posted
by
Post not yet marked as solved
4 Replies
2.1k Views
We use Rest API POST call to connect to some external Https endpoints. This worked for years, but not clients on 16.2 have the problem that out of a sudden the calls are blocked. Then nothing works, and our app thinks it's offline (for this call) but it's not offline since other services are. The only wat to fix this is to Restart the app fully. Then it's working for some while. Is their something changed in IOS 16, that its blocking an endpoint when you do to many calls? It's for prints and pin payment, so we do calls like this continuously. Here the error we get when it goes wrong: Failed with error sessionTaskFailed(error: Error Domain=NSURLErrorDomain Code=-1009 "De internetverbinding is offline." UserInfo={_kCFStreamErrorCodeKey=50, NSUnderlyingError=0x282afcc30 {Error Domain=kCFErrorDomainCFNetwork Code=-1009 "(null)" UserInfo={_NSURLErrorNWPathKey=satisfied (Path is satisfied), interface: en0[802.11], ipv4, dns, _kCFStreamErrorCodeKey=50, First we did do the call like this: urlRequest.setValue(self.getToken(), forHTTPHeaderField: "Authorization") urlRequest.setValue("text/plain", forHTTPHeaderField: "Content-Type") urlRequest.addValue("application/json", forHTTPHeaderField: "Accept") urlRequest.httpMethod = "POST" urlRequest.httpBody = request.data let config = URLSessionConfiguration.default config.timeoutIntervalForRequest = TimeInterval(5) config.timeoutIntervalForResource = TimeInterval(5) config.waitsForConnectivity = false let session = URLSession(configuration: config) let task = session.dataTask(with: urlRequest) { responseData, response, error in var isPosted = false if let err = error { Logger.debug("AWS-Api: \(request.identifer) - Failed with " + "error \(err), retrying after few seconds") var newReq = request newReq.noRetry += 1 self.addRequest(newReq) } else if let resData = responseData, let res = response { isPosted = self.processAWSResponse(request.identifer, data: resData, postData: request.data, response: res) } session.invalidateAndCancel() return promise(.success(isPosted)) } task.resume() } To debug we also updated it and use Alomfire. But unfortunately both dont work. In IOS 15 no problems are their. All the endpoints are https://
Posted
by
Post not yet marked as solved
4 Replies
981 Views
memory leak in when working with URLSession webSocketTask introductory command line app, mac os Ventura 13.2.1 the first leak is fixed on the URLSessionWebSocketDelegate delegate func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didOpenWithProtocol protocol: String?) further when calling receive closures or through func receive() async throws -> URLSessionWebSocketTask.Message the system is constantly leaking memory In order to understand how sad everything is, I recommend opening 20-50 sockets in parallel for large data streams, as an example, financial exchanges per day of work, 0.2-1 gigabytes of leakage will accumulate there is one suggestion, maybe it will help fix the bug, it is connected with another leak in the system that appears in the absence of user interactions, example if we create 20-50 swiftUI labels and start updating them fast enough 5-10 times per second and stop interacting with the mouse, keyboard and touchbar, we will get a memory leak when the old label data is not destroyed by the system - and without touching the keyboard, the mouse in an hour several gigabytes will leak us, then if you move the mouse or press a button on the keyboard, the system will clear the memory
Posted
by
Post not yet marked as solved
1 Replies
807 Views
I’m working on an independent watchOS app which is primarily designed to to collect and periodically send location updates to a server. The UI features a toggle that allows the user to turn this capability on or off at their discretion. The typical use case scenario would be for the user to turn the toggle on in the morning, put the app in the background and then go about their day. Given the limitations and restrictions regarding background execution on watchOS, in an ideal situation, I would be able to upload the stored location updates about every 15-20 minutes. With an active complication on the watch face, it’s my understanding that this should be possible. I’ve implemented background app refresh and indeed, I do see this reliably being triggered every 15-20 minutes or so. In my handle(_:) method, I process the WKApplicationRefreshBackgroundTask like this: func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) { backgroundTasks.forEach { task in switch task { case let appRefreshBackgroundTask as WKApplicationRefreshBackgroundTask: // start background URL session to upload data; watchOS will perform the request in a separate process so that it will continue to run even if our app gets // terminated; when the system is done transferring data, it will call this method again and backgroundTasks will contain an instance of // WKURLSessionRefreshBackgroundTask which will be processed below startBackgroundURLSessionUploadTask() scheduleNextBackgroundAppRefresh() appRefreshBackgroundTask.setTaskCompletedWithSnapshot(false) case let urlSessionTask as WKURLSessionRefreshBackgroundTask: // add urlSessionTask to the pendingURLSessionRefreshBackgroundTasks array so we keep a reference to it; when the system completes the upload and // informs us via a URL session delegate method callback, then we will retrieve urlSessionTask from the pendingURLSessionRefreshBackgroundTasks array // and call .setTaskCompletedWithSnapshot(_:) on it pendingURLSessionRefreshBackgroundTasks.append(urlSessionTask) // create another background URL session using the background task’s sessionIdentifier and specify our extension as the session’s delegate; using the same // identifier to create a second URL session allows the system to connect the session to the upload that it performed for us in another process let configuration = URLSessionConfiguration.background(withIdentifier: urlSessionTask.sessionIdentifier) let _ = URLSession(configuration: configuration, delegate: self, delegateQueue: nil) default: task.setTaskCompletedWithSnapshot(false) } } } And here is how I'm creating and starting the background URL session upload task: func startBackgroundURLSessionUploadTask() { // 1. check to see that we have locations to report; otherwise, just return // 2. serialize the locations into a temporary file // 3. create the background upload task let configuration = URLSessionConfiguration.background(withIdentifier: Constants.backgroundUploadIdentifier) configuration.isDiscretionary = false configuration.sessionSendsLaunchEvents = true let backgroundUrlSession = URLSession(configuration: configuration, delegate: self, delegateQueue: nil) let request: URLRequest = createURLRequest() // this is a POST request let backgroundUrlSessionUploadTask = backgroundUrlSession.uploadTask(with: request, fromFile: tempFileUrl) backgroundUrlSessionUploadTask.countOfBytesClientExpectsToSend = Int64(serializedData.count) // on average, this is ~1.5 KB backgroundUrlSessionUploadTask.countOfBytesClientExpectsToReceive = Int64(50) // approximate size of server response backgroundUrlSessionUploadTask.resume() } Note that I'm not setting the .earliestBeginDate property on the backgroundUrlSessionUploadTask because I'd like the upload to start as soon as possible without any delay. Also, this same class (my WatchKit application delegate) conforms to URLSessionTaskDelegate and I have implemented urlSession(_:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:) and urlSession(_:task:didCompleteWithError:). In my testing (on an actual Apple Watch Ultra running watchOS 9.3.1), I've observed that when the system performs the background app refresh, I always receive a callback to myhandle(_:) method. But when I start the background URL session upload task (in startBackgroundURLSessionUploadTask()), I was expecting that when the upload completes, I'd receive another call to myhandle(_:) method with an instance of WKURLSessionRefreshBackgroundTask but this doesn't seem to happen consistently. Sometimes I do see it but other times, I don't and when I don't, the data doesn't seem to be getting uploaded. On a side note, most of the time, startBackgroundURLSessionUploadTask() gets called as a result of my code handling a background app refresh task. But when the user turns off the toggle in the UI and I stop the location updates, I need to report any stored locations at that time and so I call startBackgroundURLSessionUploadTask() to do that. In that specific case, the upload seems to work 100% of the time but I definitely don't see a callback to my handle(_:) method when this occurs. Am I wrong in expecting that I should always be getting a callback to handle(_:) when a background URL session upload task completes? If so, under what circumstances should this occur? Thanks very much!
Posted
by
Post not yet marked as solved
5 Replies
1.1k Views
I understand that the DeviceActivityMonitor extension is designed to be very lightweight, and the system terminates the extension as soon as its callback functions return. However, I want to save values to UserDefaults inside the extension's callback functions. This creates concurrency issues for my app because the documentation for UserDefaults states that "When you set a default value, it’s changed synchronously within your process, and asynchronously to persistent storage and other processes." In order to guarantee that these values are persisted before the extension terminates my app, I want to call UserDefaults.synchronize(), but its documentations states that it's "unnecessary and shouldn't be used." Furthermore, it's listed under "Legacy" but not marked deprecated. Is synchronize() the recommended way to solve my concurrency problem? Or could there be a better way to wait for storage synchronization before returning from a synchronous function?
Posted
by
Post marked as solved
9 Replies
2.1k Views
I have created a POC to implement various types of download in SwiftUI. The project is available at https://github.com/curia-damiano/SwiftUIDownloader. This project has always worked, but for some reasons it doesn't work anymore. The app downloads files like https://speed.hetzner.de/100MB.bin; if I try to another files, for example https://file-examples.com/wp-content/uploads/2017/11/file_example_MP3_5MG.mp3, it still works perfectly. The error that I get is: 2023-04-16 18:42:20.665139+0200 SwiftUIDownloader[10442:425026] Task <54E67F7F-7822-4429-9943-12DA94DDCB27>.<1> HTTP load failed, 446/0 bytes (error code: -1005 [4:-4]) 2023-04-16 18:42:20.666751+0200 SwiftUIDownloader[10442:425023] Task <54E67F7F-7822-4429-9943-12DA94DDCB27>.<1> finished with error [-1005] Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost." UserInfo={_kCFStreamErrorCodeKey=-4, NSUnderlyingError=0x6000015a3930 {Error Domain=kCFErrorDomainCFNetwork Code=-1005 "(null)" UserInfo={NSErrorPeerAddressKey=<CFData 0x60000382c730 [0x1bbb34418]>{length = 16, capacity = 16, bytes = 0x100201bb58c6f8fe0000000000000000}, _kCFStreamErrorCodeKey=-4, _kCFStreamErrorDomainKey=4}}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <54E67F7F-7822-4429-9943-12DA94DDCB27>.<1>, _NSURLErrorRelatedURLSessionTaskErrorKey=( "LocalDataTask <54E67F7F-7822-4429-9943-12DA94DDCB27>.<1>" ), NSLocalizedDescription=The network connection was lost., NSErrorFailingURLStringKey=https://speed.hetzner.de/100MB.bin, NSErrorFailingURLKey=https://speed.hetzner.de/100MB.bin, _kCFStreamErrorDomainKey=4} I've also tried to troubleshoot the UrlSession, but then from the Console app I don't get any clear information about the cause of the error. I've also tried the app on old iPhone that had old builds of the app, and they have this error now - so I am sure that it is something that has changed on the server. Can anyone please help me in understanding what I can change to make the download to work again?
Posted
by
Post not yet marked as solved
6 Replies
898 Views
To download files, we have two NSURLSession objects. One configured for foreground downloads and one for background downloads. Initially, we download user-requested files in the foreground using downloadTaskWithRequest, because foreground downloads are faster than background downloads. We then also start a background task for each download using beginBackgroundTaskWithName:expirationHandler:. This background task's expiration handler starts a background download if the download didn't complete in the foreground. It cancels the foreground download with resume data using cancelByProducingResumeData. A background download task is then started using downloadTaskWithResumeData. Now, testing has shown that background download tasks resume correctly (the urlSession(_:downloadTask:didResumeAtOffset:expectedTotalBytes:) callback is called by iOS) if the background task is started immediately. However, iOS can decide to start these background download tasks later. As a sidenote, the isDiscretionary property of our background download session is set to the default, which should be false. The issue we have is that background downloads that are resumed several minutes (6,5 minutes in the session I'm currently looking at) after their original foreground download was cancelled, are not resumed properly. They download the remaining part of the file, but the first part that was downloaded in the foreground is lost. What could have happened? Perhaps the temporary file has been deleted in the meantime? Is there some way to maintain this file or detect this case?
Posted
by
Post not yet marked as solved
3 Replies
979 Views
Dear Experts, PHAsset.creationDate is an NSDate, which does not have a timezone associated with it, right? Consider a photo viewer app. If I take a photo of the sunrise at 0600 local time while I am away, when I get home and view the photo in the app, I believe I want the timestamp shown with the photo to be 0600. Do you agree? But NSDate is just a time-point, and I don't think Foundation (or anything else in iOS) has a type that combines a time-point with a time zone. Nor does PHAsset have any other useful attributes - unless I were to determine the time zone from the location! Am I missing anything?
Posted
by
Post marked as solved
4 Replies
1.4k Views
I’ve been trying to debug a seemingly random issue that involves dates, timezones, formatters and locales. I wanted to make sure I got my basics right. This I a test that passes “locally” as well as on a second computer but failed on a third. It should come down to this code once I strip away all the noise. func testExample() throws { //formatter to create date from string let DateFormatterSecondsFromGmT = DateFormatter() //notice how the order is different to the other formatter DateFormatterSecondsFromGmT.dateFormat = "dd/MM/yyyy HH:mm" //format first DateFormatterSecondsFromGmT.timeZone = TimeZone(secondsFromGMT: 0) DateFormatterSecondsFromGmT.locale = Locale(identifier: "en_GB") //locale second let string = "08/03/2023 12:10" //date the test failed (approx.): 21 Apr 2023, 11:20:32 let date = DateFormatterSecondsFromGmT.date(from: string) ?? Date() //formatter to create string from date let DateFormatterUTC = DateFormatter() DateFormatterUTC.timeZone = TimeZone(identifier: "UTC") DateFormatterUTC.locale = Locale(identifier: "en_GB") DateFormatterUTC.dateFormat = "HH:mm" let actual = DateFormatterUTC.string(from: date) //On the computer that failed, this date was at 17:10 (i.e. off by 5 hours) let expected = "12:10" //One case where actual was 17:10 and expected 12:10. XCTAssertEqual(actual, expected) } According to the Technical Q&A QA1480 NSDateFormatter and Internet Dates, when using a fixed-format date "you should first set the locale of the date formatter to something appropriate for your fixed format. In most cases the best locale to choose is 'en_US_POSIX'". Based on the TN, "On iOS, the user can override the default AM/PM versus 24-hour time setting, which causes NSDateFormatter to rewrite the format string you set". Emphasis mine. AFAIK the DateFormatter does not log a warning so I am not sure exactly what is the underlying cause for the test to fail. Also, It’s not immediately obvious to me looking at the code what could be going wrong, given that both formatters have a fixed locale (and for what is worth timezone) which leads me to believe the DateFormatter did not rewrite the format string set. On that note. I understand that setting the TimeZone to the DateFormatter will take that into account when formatting a Date to a String. Does setting the Timezone also play a role when converting a String to a Date? If so, how? Ideally, if possible, would be good for me to understand how the test ended up failing. In other words, how can I reproduce the failure which should then give me a clue into what is wrong and coming up with a solution to the root cause.
Posted
by