Leaving dispatchGroup with DEFER cause a crash [closed] - ios

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I have an rest Api async method, so use dispatch group:
let dispatchGroup = DispatchGroup()
dispatchGroup.enter()
Task.do { result in
defer { dispatchGroup.leave() }
//...
}
this make a crash Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
But
let dispatchGroup = DispatchGroup()
dispatchGroup.enter()
Task.do { result in
//...
dispatchGroup.leave()
}
don't crash. Why?

Point 1 is : defer is called when scope of your function ends ...
Point 2 is : dispatchGroup enter should be equal to leaves otherwise your application will crash

Related

C in Swift Project [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed last month.
Improve this question
I'm not too familiar with trying to use C functions from an external library in a Swift project.
I have the following code (commented with the necessary typedefs):
func sadp40() {
let start: Int32 = SADP_Start_V40(SadpDataCallBack, 0, nil) // <-- Error occurs here.
}
func SadpDataCallBack(lpDeviceInfo: SADP_DEVICE_INFO_V40?, pUserData: UnsafeMutableRawPointer) -> () {
// debugPrint(lpDeviceInfoV40?.struSadpDeviceInfo.szIPv4Address as Any)
}
/*
typedef void (CALLBACK *PDEVICE_FIND_CALLBACK_V40)(const SADP_DEVICE_INFO_V40 *lpDeviceInfo, void *pUserData);
CSADP_API BOOL CALLBACK SADP_Start_V40(PDEVICE_FIND_CALLBACK_V40 pDeviceFindCallBack, int bInstallNPF, void* pUserData);
*/
In the function sadp40() I'm receiving a Type of expression is ambiguous without more context error but I'm not sure how to fix it or why it is occurring.
Edit:
Option + Click in XCode:

Dispatch Group Multiple Joined Swift [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
Hi everyone i have a question about a problem that i would like to do in swift and to see the best possible way to do that. I currently have an approach that i don't like and would be good if i can get some ideas about it.
Here it is the problem:
DispatchQ serial which is started
Then another Thread starts and waits for a completion block that returns 1 element per run
That thread will run multiple times and it will give 1 element each time until it returns all elements
The code shouldn't proceed forward and has to wait for all the elements to be collected in a array
After the array is full then the code can proceed forward.
Example with LocationManager:
Location manager starts fetching location
It output the location each time it finds a new location
At the end i have to collect all the locations i have gotten in 10 sec for example
Then proceed the work of the current thread
Example code:
var queue = DispatchQueue("q")
queue.async {
var locationCollected = Array<Location>()
// this will output multiple times
getLocation { location in
// add location to the collection
locationCollected.append(location)
}
// the current Q need to wait until all results are collected
return locationCollected
}
func getLocation() -> Location {
// this is the function that will return location
self.manager?.location(completion: { location in
// will provide location and update
completion(location)
}
}
Thank you much appreciated the help
If you want to adopt a linear flow of code approach then you can adopt the new async/await construct but that will limit your iOS versions.
In general blocking threads is best avoided as it can cause deadlocks. You should use completion handlers to get your asynchronous result rather than blocking.
For the purposes of this answer I will stick with the approach in your question.
Based on the requirements in your question, let's create a function that:
Fetches locations for a specified duration
Only fetches one location at a time
Provides the fetched location in an array
Is, itself, an asynchronous function
We need to ensure only a single location fetch is active at a time, which we can do with a DispatchSemaphore
func getLocations(for duration: TimeInterval, completion: (([Location])->Void)) {
var queue = DispatchQueue("q")
queue.async {
let semaphore = DispatchSemaphore(0)
var locationCollected = [Location]()
let startTime = Date()
while (startTime.timeIntervalSinceNow > -duration) {
getLocation { location in
locationCollected.append(location)
semaphore.signal()
}
semaphore.wait()
}
completion(result)
}
}

Swift: Enums with stored properties not thread safe even when mutated using a serial queue

This issue relates to another issue reported on the Apple Developer forum titled How to avoid Data Races in deinit from 4 years ago. I am seeing crashes in production related to associated data and outlined consume code added by the compiler to deinitialize enums with associated data that contain reference types.
When trying to find if someone else has faced the same issue, I stumbled across the above post. I reduced the example from that post to a simpler example below and reliably get a crash due to bad access. (I ran this in Playground and got the crash but no stack trace)
import Foundation
class Racer {
let queue = DispatchQueue(label: "Racer-\(UUID())")
var value: String? = "" // Desugars to Optional<String>, an enum
func race() {
queue.async {[weak self] in
self?.value = UUID().uuidString
}
}
}
let racer = Racer()
while true {
racer.race()
}
error: Execution was interrupted, reason: EXC_BAD_ACCESS (code=1, address=0x357d20cc94c0).
Is this a bug in Swift that has yet to be patched?

Adding dependency of one BlockOperation on another is not working properly in swift

I have multiple api's in a controller and after successful response I have to reload the UITableView.
For now I started with two api having second api dependency on first one using BlockOperation and DispatchGroup in it.
First in viewDidLoad:
getDataFromAllApis {
self.tableView.reloadData()
}
Then I added the method:
func getDataFromAllApis(completion: #escaping (() -> Void)) {
let queue = OperationQueue()
let getFirstDataOperation = BlockOperation {
let group = DispatchGroup()
group.enter()
self.getFirstDataFromApi {
group.leave()
}
group.wait()
}
queue.addOperation(getFirstDataOperation)
let getSecondDataOperation = BlockOperation {
let group = DispatchGroup()
group.enter()
self.getSecondDataFromApi {
group.leave()
}
group.notify(queue: .main) {
completion()
}
}
queue.addOperation(getSecondDataOperation)
getSecondDataOperation.addDependency(getFirstDataOperation)
}
The problem that I am facing here is getSecondDataOperation executes first and returns to the tableview reload part.
Am I missing something here or there can be a different approach for it? Any help will be appreciated.
I have tried going through this post :
How can you use Dispatch Groups to wait to call multiple functions that depend on different data?
You are way overthinking this. Just call the second API from the completion handler of the first API. No operations, no dispatch groups, no nothing.
self.getFirstDataFromApi {
self.getSecondDataFromApi {
// call the completion handler
}
}
As for why your code didn't work, it's because you didn't do what the linked answer said to do!
How can you use Dispatch Groups to wait to call multiple functions that depend on different data?
It said to do this:
getSecondDataOperation.addDependency(getFirstDataOperation)
queue.addOperation(getFirstDataOperation)
queue.addOperation(getSecondDataOperation)
That isn't what you did. You did this:
queue.addOperation(getFirstDataOperation)
queue.addOperation(getSecondDataOperation)
getSecondDataOperation.addDependency(getFirstDataOperation) // too late
(However, that post, while ingenious, is not what I would do in this situation. If I wanted to sequentialize download operations, I would use the technique described here: https://fluffy.es/download-files-sequentially/. Or, in iOS 13, I'd use the Combine framework, as I describe here: https://stackoverflow.com/a/59889993/341994.)

Why is defer block executed before a closure finishes in the same function [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I wrote the following function to add a map annotation that uses CLGeocoder() to resolve the location name given a coordinate. I use a defer block to get the resolved location name. However, the defer block seems to finish before the closure finishes. Why?
Below is my code:
func addAnnotation(gestureRecognizer: UIGestureRecognizer) {
var locationNameStr = ""
defer {
let newPin = Pin(dictionary: locationDictionary, context: sharedContext)
newPin.name = locationNameStr
do {
//persist the new pin to core data
try sharedContext.save()
showPinOnMap(newPin)
} catch let error as NSError {
print("error saving the new pin in context")
}
}
// use CLGeocoder to resolve the location name as title of the annotation
CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: newCoordinate.latitude, longitude: newCoordinate.longitude), completionHandler: {(placemarks, error) -> Void in
if error != nil {
print("reverse geocoding failed with error: \(error)")
//return
} else if placemarks!.count > 0 {
let firstPlace = placemarks![0] as CLPlacemark
if firstPlace.country != nil {
locationNameStr = "a place in \(firstPlace.country!)"
}
else if firstPlace.locality != nil {
locationNameStr = "a place in \(firstPlace.locality!)"
}
print("location name: \(locationNameStr)")
}
})
}
You misunderstand what a defer block does.
It is a block of code that gets executed when you exit the current scope.
When you execute an async method with a completion block, it returns immediately and execution goes on to to the next line. The called method takes your completion block and saves it for later.
Your method then finishes and execution passes out of the method's scope. The defer block gets executed. At some later time, the async method finishes it's background work and calls the completion handler that you passed to it. With an async method that will ALWAYS happen after the calling method returns.
#fqdn has the right idea. Put your cleanup code in the completion block. That's where it belongs.
reverseGeocodeLocation(_:completionHandler:) executes asynchronously, it makes sense that the code in your defer block is executing before the closure passed as the completionHandler argument is invoked
is there a reason that the code in your defer block can't be moved in to your completion handler?

Resources