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

337 Posts
Sort by:
Post not yet marked as solved
0 Replies
27k Views
Debugging code that runs in the background on iOS is tricky because the act of running your app in the debugger affects how it behaves. This is especially true with URLSession background session code. I regularly see folks confused about how to test and debug such code, and this is my attempt to help with that. If you have questions or comments about this, start a new thread and tag it with Foundation and CFNetwork so that I see it. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Testing Background Session Code Testing an app that uses a URLSession background session is tricky because of the differences between the test environment and the production environment. This post explains those differences and describes how you can effectively test your background session code. Confusing Behaviours When testing background session code you might encounter four common sources of confusion: When you run your app from Xcode, Xcode installs the app in a new container, meaning that the path to your app changes. Background sessions should deal with this path change correctly, but there have been times in the past where that’s not been the case. Note If you encounter a problem with a background session mishandling a container path change, please report that as a bug. Xcode’s debugger prevents the system from suspending your app. If you run your app from Xcode, or you attach to the process after launch, and then move your app into the background, your app will continue executing in situations where the system would otherwise have suspended it. Simulator may not accurately simulate app suspend and resume. Note This is supposed to work but there have been problems with it in the past (r. 16532261). If you see this problem on modern versions of Xcode, please report it as a bug. When you remove an app from the multitasking UI (aka force quit it), the system interprets that as a strong indication that the app should do no more work in the background, and that includes URLSession background tasks. Testing Recommendations Given the above, my recommendation is that you test your app as follows: Test on a real device, not in Simulator. Run your app from the Home screen rather than running it from Xcode. Don’t use force quit to test the ‘relaunch in the background case’. Doing this avoids all of the issues described above, resulting in a run-time environment that’s much closer to what your users will see. Debugging Background Session Code If you encounter problems that you need to debug, you have two options. The first is to use logging. Your app needs good logging support anyway; without that, it’ll be impossible to debug problems that only show up in the field. Once you’ve taken the time to create this logging, use it to debug problems during development. I recommend that you log to the system log. For more on that, see Your Friend the System Log. If you have a specific problem that you must investigate with the debugger, run your app from the Home screen and then attach to the running process by choosing Debug > Attach to Process in Xcode. Alternatively, use “Wait for executable to be launched” in the Info tab of the Xcode’s scheme editor. IMPORTANT As mentioned above, the debugger prevents your app from suspending. If that’s a problem, you can always detach and then reattach later on. About Force Quit The behaviour of background sessions after a force quit has changed over time: In iOS 7 the background session and all its tasks just ‘disappear’. In iOS 8 and later the background session persists but all of the tasks are cancelled. Note You can use the NSURLErrorBackgroundTaskCancelledReasonKey property of the error to find out why a task was cancelled. Test that your app handles the force quit behaviour of the platforms you support. However, don’t use force quit to test how your app deals with the ‘relaunch in the background case’. The best way to test the ‘relaunch in the background case’ is to have your app terminate itself by calling exit. The system does not interpret this as a force quit, and thus will relaunch your app in the background when your background session needs attention. There two ways to go about this: Simply add a Quit button that calls exit. Add some setting that causes your app to call exit shortly after moving to the background. You’ll need to use a UIApplication background task to prevent your app from being suspended before it gets a chance to quit. IMPORTANT The suggestions above are for testing only. Do not include a Quit button in your final app! This is specifically proscribed by QA1561. Starting From Scratch While bringing up a feature that uses background sessions, it’s often useful to start from a clean slate on launch; this prevents tasks from a previous debugging session confusing the current debugging session. You have a number of options here: If you’re testing in Simulator, Device > Erase All Content and Settings is an excellent way to wipe the slate completely clean. On both Simulator and a real device, you can delete your app. This removes the app, everything in the app’s container, and everything created by the app, including any background sessions. You can also take advantage of the invalidateAndCancel() method, which will cancel any running tasks and then invalidate the session. There are a few ways to use invalidateAndCancel(): During active development it might make sense for your app to call this on launch, guaranteeing that you start with a clean slate every time. Alternatively, you could keep track of your app’s install path and call it on launch if the install path has changed. You might add a ‘hidden’ UI that invalidates the session. This is helpful when you encounter a problem and want to know whether it’s caused by some problem with the background session’s persistent state. Revision History 2023-07-12 Fixed the formatting. Made significant editorial changes. 2018-05-03 Added a discussion of force quit. Also made major editorial changes, restructuring the document to be easy to read. 2015-08-18 First posted. (r. 22323379)
Posted
by
Post not yet marked as solved
0 Replies
3.3k Views
There are many cases where you want to do long-running network operations in a short-lived app extension. For example, you might be creating a share extension that needs to upload a large image to an Internet server. Doing this correctly is quite tricky. The rest of this post describes some of these pitfalls and explains how to get around them. Just by way of context: Most of the following was written during the iOS 8.1 timeframe, although AFAIK there’s been no specific changes in this space since then. The specific focus here is a share extension, although the behaviour is likely to be similar for other short-lived extensions. I wasn’t using SLComposeServiceViewController, although I have no reason to believe that makes a difference. I was testing on a device, not the simulator. In my experience the simulator is much less likely to terminate a share extension, which affects how things behave as I’ll explain later. My app and its share extension have an app group in common. I started by verifying that this app group was working as expected (using UserDefaults). The URLSession must be in that app group; set this via the sharedContainerIdentifier property of the URLSessionConfiguration object you use to create the session. The app and the share extension must use the same URLSession background session identifier (the value you pass in to background(withIdentifier:) when creating the configuration that you use to create the session). When an URLSession background session is shared like this, it’s critical to understand that the session only allows one process to ‘connect’ to it at a time. If a process is connected to the session and another tries to connect, the second process has its session immediately invalidated with NSURLErrorBackgroundSessionInUseByAnotherProcess. The connected session is the one that receives the session’s delegate callbacks. IMPORTANT If callbacks are generated when no process is connected, the background session resumes (or relaunches) the app rather than the extension. If a process is connected to a session and is then suspended or terminates, the session disconnects internally. If the process was terminated, the reconnection happens when your code creates its URLSession object on next launch. If the process was suspended, the reconnect happens when the app is resumed with the application(_:handleEventsForBackgroundURLSession:completionHandler:) delegate callback (and remember that this is always the app, not the extension, per the previous paragraph). The only way to programmatically disconnect from a session is to invalidate it. The expected behaviour here is that the extension will start an URLSession task and then immediately quit (by calling completeRequest(returningItems:completionHandler:)). The system will then resume (or relaunch) the container app to handle any delegate callbacks. When the system resumes or relaunches the container app to handle background session events, it calls application(_:handleEventsForBackgroundURLSession:completionHandler:). The container app is expected to: Save away the completion handler. Reconnect to the session, if necessary. This involves creating the URLSession object if it doesn’t currently exist. Handle delegate events from that session. Invalidate the session when those events are all done. The app knows this because the session calls the urlSessionDidFinishEvents(forBackgroundURLSession:) delegate callback. Call the completion handler that was saved in step 1. This leaves the app disconnected from the session, so future invocations of the extension don’t have to worry about the NSURLErrorBackgroundSessionInUseByAnotherProcess problem I mentioned earlier. This design works best if each extension hosted by the app has its own shared session. If the app hosts multiple extensions, and they all used the same shared session, they could end up stomping on each other. In my tests I’ve noticed that some annoying behaviour falls out of this design: If you start a task from an extension, it’s non-deterministic as to whether the app or extension gets the ‘did complete’ callback. If the task runs super quickly, the extension typically gets the callback. If the task takes longer, the system has time to terminate the extension and the app is resumed to handle it. There’s really no way around this. The workaround is to put the code that handles request completion in both your app and your extension (possibly sharing the code via a framework). It would be nice if the extension could disconnect from the session immediately upon starting its request. Alas, that’s not currently possible (r. 18748008). The only way to programmatically disconnect from the session is to invalidate it, and that either cancels all the running tasks (invalidateAndCancel()) or waits for them to complete (finishTasksAndInvalidate()), neither of which is appropriate. One interesting edge case occurs when the app is in the foreground while the share extension comes up. For example, the app might have a share button, from which the user can invoke the share extension. If the share extension starts an URLSession task in that case, it can result in the app’s application(_:handleEventsForBackgroundURLSession:completionHandler:) callback being called while the app is in the foreground. The app doesn’t need to behave differently in this case, but it’s a little unusual. Xcode’s debugger prevents the system from suspending the process being debugged. So, if you run your extension from Xcode, or you attach to its process some time after launch, the process will continue to execute in situations where the system would otherwise have suspended it. This makes it tricky to investigate problems with the ‘extension was suspended before the network request finished’ case. The best way to investigate any issues you encounter is via logging. Note For more information about debugging problems with background networking, see Testing Background Session Code. Keep in mind that not all networking done by your extension has to use a background session. You should use a background session for long-running requests, but if you have short-running requests then it’s best to run them in a standard session. For example, imagine you have a share extension that needs to make two requests: The first request simply gets an upload authorisation token from the server. This request is expected to finish very quickly. The second request actually uploads the file (including the upload authorisation token from the previous request), and is expected to take a long time. It makes sense to only use a background session for the second request. The first request, being short-running, can be done in a standard session, and that will definitely simplify your code. When doing this you have to prevent your extension from suspending while the short-lived request is in flight. You can use ProcessInfo.performExpiringActivity(withReason:using:) for this. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Revision History 2023-08-30 Fixed the formatting. Adopted Swift terminology throughout. Made other minor editorial changes. 2017-04-26 Moved to the new DevForums. Made many editorial changes. Added the section on Xcode’s debugger. Added a section on short-running network requests. 2014-12-05 First posted on the old DevForums.
Posted
by
Post not yet marked as solved
29 Replies
10k Views
I've recently been integrating Background Transfer Service into an application so that the user is able to download files in the background.I did most of my building/testing on an old iPhone 6 device that was running iOS 9.3.5 (I try to keep my previous device back a version of iOS). Background Transfer Service works great on this device. I am able to put 100+ download tasks into the queue and they all finish and report progress as expected after sending the application into the background and then re-opening the application.This also appears to work great on a new 5th generation iPad running iOS 10.3.Where things get weird is on my iPhone 7 Plus which is running iOS 10.3.1. The downloads kick off fine, progress is reported as expected in the didWriteData method, however if I background the application and wait ~10 seconds and re-open the application the progress never catches back up to what progress would have been done in the background and the progress never increments at all (it stays where it was when it was backgrounded). The didFinishDownloading method does end up getting called however it appears to wait until the very end of all the download tasks completions for that method to fire for all of the remaining tasks. So the didWriteData, didFinishDownloading, didCompleteWithError, etc. all happen right at the end in one burst. I have however had a few instances where my iPhone 7 Plus device running iOS 10.3.1 did show progress after bringing the app back into the foreground however those instances I could could on one hand. More often than not (9 times out of 10) the progress is never reported on this device after re-opening the application.I am at a bit of a loss and am wondering if there is a known bug we should be looking out for, and if so when we could expect a fix? Or if there are currently any known work arounds. From my testing/debugging I cannot get progress to work in my application on the iPhone 7 Plus running 10.3.1. I also had a co-worker test this as well and they also experienced this.In fact they went a step further and opened the Netflix application on their 10.3.1 iPhone 7 Plus device and began downloading a movie. Progress incremented as expected, they then backgrounded the application and waited ~20 seconds and re-opened the application, only to find the progress get stuck where it was when the app was initially backgrounded and it never moves. After a given amount of time of the progress not moving the download does eventually finish (the progress indicator disappears) and the Netflix movie is downloaded and able to be played. This is the same behavior I see above in my application.Any help with this would be greatly appreciated.Thanks in advance!Adam
Posted
by
Post not yet marked as solved
7 Replies
2.2k Views
App is crashing while a bluetooth device is disconnected. I've seen few related threads and they say "A notification delegate was not reset to nil. A fix has been applied at version 10.3.79."Following is crash log:Triggered by Thread: 0 Thread 0 name: Thread 0 Crashed: 0 libobjc.A.dylib 0x000000018544c430 objc_msgSend + 16 1 ExternalAccessory 0x000000019c07c4dc -[EAAccessoryManager _notifyObserversThatAccessoryDisconnectedWithUserInfo:] + 104 (EAAccessoryManager.m:909) 2 ExternalAccessory 0x000000019c07eddc -[EAAccessoryManager _externalAccessoryDisconnected:] + 928 (EAAccessoryManager.m:1537) 3 CoreAccessories 0x00000001a7892ccc __54-[ACCExternalAccessoryProvider ExternalAccessoryLeft:]_block_invoke + 316 (ACCExternalAccessoryProvider.m:453) 4 libdispatch.dylib 0x0000000185b6d088 _dispatch_call_block_and_release + 24 (init.c:994) 5 libdispatch.dylib 0x0000000185b6d048 _dispatch_client_callout + 16 (object.m:502) 6 libdispatch.dylib 0x0000000185b79b74 _dispatch_main_queue_callback_4CF$VARIANT$mp + 1016 (inline_internal.h:2500) 7 CoreFoundation 0x0000000186191eb0 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12 (CFRunLoop.c:1815) 8 CoreFoundation 0x000000018618fa8c __CFRunLoopRun + 2012 (CFRunLoop.c:3111) 9 CoreFoundation 0x00000001860affb8 CFRunLoopRunSpecific + 436 (CFRunLoop.c:3245) 10 GraphicsServices 0x0000000187f47f84 GSEventRunModal + 100 (GSEvent.c:2245) 11 UIKit 0x000000018f6842e8 UIApplicationMain + 208 (UIApplication.m:3949) 12 MYAPP 0x0000000100ab8d58 main + 172 (main.m:16) 13 libdyld.dylib 0x0000000185bd256c start + 4
Posted
by
Post marked as solved
15 Replies
11k Views
I read here that when using `URLSessionConfiguration.background(withIdentifier:)`, it shouldn't timeout and should try again 'till there is an available internet connection or 'till `timeoutIntervalForResource` reached out (which is set to 7 days), but in this case, I'm getting the timeout after less than 15 seconds and after that it doesn't seems to try again, also when there is an internet connection (e.g. turning off Network Link Conditioner).I haven't set anything to that time so I really don't know why this is happening, all I've done is to set `100% Loss` in Network Link Conditioner to check offline usage (which shouldn’t matter to URLSession since it using background configuration).In short:My goal is to start the session whenever there is or there isn't an internet connection and let it fetch as soon as it can, when there is an available internet connection.What happens right now is that the session is timed out and not performing the session also when there is an internet connection (e.g. turning off Network Link Conditioner).*It's important to note that when there is an available internet connection while the session is resumed, it does fetching successfully, so the issue is not with the server I'm sending the task to for sure.Here is my code:Defining session configuration:static let urlSessionConfiguration: URLSessionConfiguration = { let configuration = URLSessionConfiguration.background(withIdentifier: FilesManager.urlSessionIdentifier) configuration.sessionSendsLaunchEvents = false configuration.sharedContainerIdentifier = "myApp" return configuration }()Starting the session:let url = URL(string: "https://url.com/path")! var urlRequest = URLRequest(url: url) urlRequest.httpMethod = "POST" urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type") urlRequest.httpBody = body URLSession(configuration: FilesManager.urlSessionConfiguration, delegate: self, delegateQueue: nil).dataTask(with: urlRequest).resume()Delegate:extension FilesManager: URLSessionDataDelegate, URLSessionDelegate { func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { print("\(#function) \(error)") } }Print in console:urlSession(_:task:didCompleteWithError:) Optional(Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo={_kCFStreamErrorCodeKey=-2104, _NSURLErrorFailingURLSessionTaskErrorKey=BackgroundDataTask .<1>, _NSURLErrorRelatedURLSessionTaskErrorKey=( "BackgroundDataTask .<1>", "LocalDataTask .<1>" ), NSLocalizedDescription=The request timed out., _kCFStreamErrorDomainKey=4, NSErrorFailingURLStringKey=https://url.com/path, NSErrorFailingURLKey=https://url.com/path})If you know a better way to achieve my goal or you’re think there is something wrong in this code, please, let me know.Thanks,Ido.
Posted
by
Post not yet marked as solved
2 Replies
3.7k Views
Hi,I'm wondering would the network request be successful if a 302 redirect is placed on the server and the app doesn't explicitly implement 'willPerformHTTPRedirection' delegate?We are working on domain migrations and are concerned about backward compatibility of apps to make successful requests(200) when the url redirects are effective.Appreciate the help.
Posted
by
Post not yet marked as solved
4 Replies
3.2k Views
Parsing fixed-format date strings is tricky. For an explanation as to why, see QA1480 NSDateFormatter and Internet Dates - https://developer.apple.com/library/ios/#qa/qa1480/_index.html. However, there’s an extra gotcha when you try to parse fixed-format date strings that don’t include a time. The posts below explain this gotcha and how to get around it. If you have questions about any of this, please start a new thread here on DevForums. Make sure to tag it with Foundation so that I notice your post. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@apple.com"
Posted
by
Post not yet marked as solved
3 Replies
703 Views
I logged in to macOS with my localization language. try to perform following code. but always get "Documents". What do I miss? Apple Swift version 5.2.4 macOS 10.15.6 Xcode 11.6 code let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) if paths.count > 0 {     let doc = FileManager().displayName(atPath: paths[0])     print(doc) } result Documents
Posted
by
Post not yet marked as solved
26 Replies
9.0k Views
Hi, I am facing a strange issue in my app with iOS14 there is a intermittent crash, i am using NetServiceBrowser for MDNS discovery not sure if that is causing the problem crash log has below information: Crashed: com.apple.main-thread 0 CoreFoundation 0x1a906c4c4 CFAssertMismatchedTypeID + 108 1 CoreFoundation 0x1a8f7db0c CFRunLoopSourceRemoveFromRunLoop + 298 2 CFNetwork 0x1a96255b0 CFNetServiceBrowserStopSearch + 460 3 CoreFoundation 0x1a8f81240 CFRUNLOOPISCALLINGOUTTOASOURCE0PERFORMFUNCTION + 24 4 CoreFoundation 0x1a8f81140 CFRunLoopDoSource0 + 204 5 CoreFoundation 0x1a8f80488 CFRunLoopDoSources0 + 256 6 CoreFoundation 0x1a8f7aa40 CFRunLoopRun + 776 7 CoreFoundation 0x1a8f7a200 CFRunLoopRunSpecific + 572 8 GraphicsServices 0x1bf075598 GSEventRunModal + 160 9 UIKitCore 0x1ab840004 -[UIApplication run] + 1052 10 UIKitCore 0x1ab8455d8 UIApplicationMain + 164
Posted
by
Post not yet marked as solved
18 Replies
14k Views
My app user sometimes lost data in UserDefaults when our app launched. All or part of the data is lost. A device that has happened once is likely to happen again. This bug seems to have been around since October 2020. Not depend on any OS or hardware, and we haven’t been able to reproduce it yet. Does anyone face the same bug?
Posted
by
Post marked as solved
5 Replies
2.6k Views
Hello, I am facing an issue with NSTask (Process), NSPipe (Pipe) and NSFileHandle (FileHandle). I have an app that executes a child process (command line utility) and gets its output via Pipe instances set as standardI/O of Process instance. I can observe two logic flows: Once the child process exits, -[Process readabilityHandler] gets called where I gather the $0.availableData. Once the child process generates output (i.e. print() is executed by the child process), -[Process readabilityHandler] also gets called which makes sense. This is the case when exit() is not called by the child process (i.e. continuous execution). However, when LLDB is detached, #2 is false, i.e. -[Process readabilityHandler] is not called. Wrong behaviour also happens if I don't rely on readabilityHandler, but instead use Notification to receive changes in data availability. In such case, notification gets called continuously with empty data (even though child process does generate the output). If I don't create Pipe instance for standardI/O of the Process, then readabilityHandler does get called, but with an empty data continuously. I have created a DTS #756462540, since this doesn't make any sense. Prerequisites* app is not sandboxed Big Sur 11.0.1 (20B29) Xcode 12.3 (12C33)
Posted
by
Post not yet marked as solved
3 Replies
913 Views
Hello, For our iOS app, we're switching WebSocket client implementation from one using Poco project - https://github.com/pocoproject/poco to one based on NSURLSessionWebSocketTask. We are observing one regression which prevents us from shipping this solution though: 5-7% of calls to -[NSURLSessionWebSocketTask cancelWithCloseCode:reason:] fail to deliver given close code to server and 1006 close code (AbnormalClosure) is used instead. Our test consist of following steps: Create WebSocket using NSURLSessionWebSocketTask Send "Hello" message Close WebSocket with 1011 close code Destroy NSURLSessionWebSocketTask instance Check whether server received 1011 close code We do not perform those steps line by line, but rather use delays (~100-200ms) between each step. We perform such test 1000 times and observe 5-7% failure rate consistently. Distribution of failures is random. We did perform test on both iOS simulator and iOS devices with no observable differences. We did perform test on multiple server implementations (tornado- and node.js based ones) running on local machine (same as Xcode) and remote one We always receive "Hello" message on server 1011 close code is arbitrarily chosen for testing, but results are same for different ones, too. We did setup mitmproxy and for failed tests see following log: Error in WebSocket connection to 20.16.12.131:8080: WebSocket connection closed unexpectedly by client: TcpDisconnect(None) We did enable CFNetwork diagnostic using CFNETWORK_DIAGNOSTICS and found one difference between success and failure cases. For successful cases we see log which looks like this: default 16:27:15.831193+0200 Playground-ObjC tcp_close [C7.1:2] TCP Packets: snd 0.000s seq 1092086878:1092086879 ack 0 win 65535 len 0 [SEC] rcv 0.004s seq 3101059099:3101059100 ack 1092086879 win 65535 len 0 [S.] snd 0.000s seq 1092086879:1092086879 ack 3101059100 win 4117 len 0 [.] snd 0.002s seq 1092086879:1092087279 ack 3101059100 win 4117 len 400 [P.] rcv 0.001s seq 3101059100:3101059100 ack 1092086879 win 2058 len 0 [.] rcv 0.000s seq 3101059100:3101059100 ack 1092087279 win 2052 len 0 [.] rcv 0.015s seq 3101059100:3101059229 ack 1092087279 win 2052 len 129 [P.] ECT0 snd 0.000s seq 1092087279:1092087279 ack 3101059229 win 4113 len 0 [.] snd 0.003s seq 1092087279:1092087289 ack 3101059229 win 4113 len 10 [P.] rcv 0.002s seq 3101059229:3101059229 ack 1092087289 win 2052 len 0 [.] snd 0.017s seq 1092087289:1092087297 ack 3101059229 win 4113 len 8 [P.] snd 0.001s seq 1092087297:1092087298 ack 3101059229 win 4113 len 0 [F.] rcv 0.000s seq 3101059229:3101059229 ack 1092087297 win 2052 len 0 [.] rcv 0.001s seq 3101059229:3101059233 ack 1092087297 win 2052 len 4 [P.] ECT0 Last packet 0ms ago. So it's something related to "tcp_close" and seems to log whole TCP packets that were exchanged during connection. For failed cases such log is not present. One additional log we see potentially interesting (but were not able to confirm its meaning or relation to failed cases) comes from runningboardd: default 16:27:15.830447+0200 runningboardd Invalidating assertion 33-1364-23682 (target:[applicationorg.example.app:1364]) from originator [applicationorg.example.app:1364] So that's where we are right now and we have no idea where to dig next. We wonder if anyone else have seen such problem or can point us to any direction we could try next. Thanks much, Damian & Maciek
Posted
by
Post not yet marked as solved
8 Replies
2.4k Views
I am working on an application where there is a need to do a specific API only through Mobile Data and not wifi, allowing other API calls to be done using the available network type whether cellular data or wifi or .... Is there a way to force use Mobile data usage even if WIFI is ON on this API call.
Posted
by
Post marked as solved
5 Replies
1.8k Views
I have a working background URLSession. I know that upon creating an URLSession with the same session identifier I get a "background URLSession with identifier x already exists" message. I know that I can store the session and call .finishTasksAndInvalidate() on it if needed. My use case is that if the application terminates, and the user relaunches the application before the background task completes, I need to be able to check if a background URLSession with the same identifier exists, and if it does, restitute the application state with the same handlers (so that I can update a UIProgressView for example). I have two questions: How do I check that a background URLSession with a given identifier already exists? Does the AppDelegate completion handler still get called if the application was terminated and relaunched?
Posted
by
Post not yet marked as solved
3 Replies
2k Views
Given that type UUID is a struct I thought it would be Sendable. But the compiler generates a warning: struct S: Sendable { var int: Int var id: UUID // <-- Stored property 'id' of 'Sendable'-conforming struct 'S' has non-sendable type 'UUID' }
Posted
by
Post not yet marked as solved
9 Replies
2.6k Views
Hi! I'm looking for some insight and guidance on using the Foundation.Process type with a PTY (Psuedo Terminal) so that the subprocess can accept input and behave as if it was running via a terminal. The reason for needing a PTY is that for programs like ssh or in my case (xcodes) which ask for user input including passwords, running these via Foundation.Process does not display the prompts to the user as the output is usually buffered (this works fine in the Xcode debugger console but when running via a real terminal that is buffered the prompts are never displayed in the terminal) Looking at other threads it seems like correct approach here is create a PTY and use the filehandles to attach to the Process. While I've got this to work to the point where prompts are now shown, I cant seem to figure out how to pass input back to the process as these are being controlled by the PTY. Here is my Process setup: let process = Process() // Setup the process with path, args, etc... // Setup the PTY handles var parentDescriptor: Int32 = 0 var childDescriptor: Int32 = 0 guard Darwin.openpty(&parentDescriptor, &childDescriptor, nil, nil, nil) != -1 else {   fatalError("Failed to spawn PTY") } parentHandle = FileHandle(fileDescriptor: parentDescriptor, closeOnDealloc: true) childHandle = FileHandle(fileDescriptor: childDescriptor, closeOnDealloc: true) process.standardInput = childHandle process.standardOutput = childHandle process.standardError = childHandle With this setup I then read the parent handle and output any result it gets (such as the input prompts): parentHandle?.readabilityHandler = { handle in   guard let line = String(data: handle.availableData, encoding: .utf8), !line.isEmpty else {     return   }   logger.notice("\(line)") } When process.run() is executed the program runs and I can see it asks for Apple ID: input in my terminal, however, when typing input into the terminal the process does not seem to react to this input. I've tried forwarding the FileHandle.standardInput: FileHandle.standardInput.readabilityHandler = { handle in   parentHandle?.write(handle.availableData) } But this doesn't seem to work either. What is the recommended way to setup a PTY with Foundation.Process for executing arbitrary programs and having them behave as if they were being run in a terminal context? Most of the resources I found online are about other languages and I'd like to stick with Foundation.Process vs. doing anything custom in C/C++ if possible as it just makes it easier to reason about / maintain. The resources for Swift on this topic are very lacking and I've checked out some open source projects that claim to do this but most require manually sending input to the PTY handle vs. accepting them from the user in a terminal. Any insight / help is very much appreciated!
Posted
by
Post not yet marked as solved
3 Replies
1.8k Views
Hi, I thought that with Exporting String with localization in all files but it didn't. It export all SwiftUI Text and Button Strings but thats it. I had a file where I have. String(localized: “Hello, world!”, comment: “Hello”) It is in project and it is passed to the view later. Tired in Beta 5 and RC Thanks
Posted
by
Post marked as solved
6 Replies
2.9k Views
I tried to build LocalizedKeyString using String's new Initializer. String(localized: "hello",locale: locale) When I change the language setting of the device, everything works as expected. However, when I try to get the string in a specific language using the specified Locale, I can only ever get the string in .current. String(localized: "hello",locale: Locale(identifier: "zh-cn"))     func getString(locale:Locale) -> String{          String(localized: "hello",locale: locale)     } If you change the display language of the project (or the language setting of the device), the text in Text is always displayed correctly. Text(getString(locale:.current)) However, the code in onAppear print(getString(locale:Locale(identifier: "zh-cn"))) It only displays the same content as Text, but not the specified Chinese. Is it my fault that the new Initializer The understanding is not correct, or the bug of String init(localized keyAndValue: String.LocalizationValue, table: String? = nil, bundle: Bundle? = nil, locale: Locale = .current, comment: StaticString? = nil) FB number: FB9675845
Posted
by
Post not yet marked as solved
1 Replies
1.3k Views
In Xcode 13, using the 14.5 and 15.0 simulators, when I use UserDefaults to save preferences for the user, the defaults seem to go away when the app quits (I am using the home button / app switcher / slide up gesture to quit the app in the simulator). This problem does not occur when using my actual devices (iPad and iPhone). [userDefaults synchronize] returns YES, however I am getting nil for the key I saved upon next launch. Note: I am using NSKeyedArchiver archivedDataWithRootObject with requiresSecureCoding set to YES for some keys, however the first key is not using NSKeyedArchiver and is also returning nil.
Posted
by