Completion Block seemingly being ignored - ios

So I have a function with a completion block that handles animation and a function calling that function. During the function call the completion block is seemingly skipped over because no print lines are printed. I have tried putting the code to be executed into the main queue but it has not yielded any results. Here is how I'm calling the function:
runAnimations(past.count, currentIteration: 0, animationsArray: past, completion: {
finished in
var randomr = self.randomInRange(0,hi: 3)
println("sell")
past.append(randomr)
for i in past123{
if(past.count >= 10){
}
else{
// have tried with and without dispatch_async.. neither print little did I know
dispatch_async(dispatch_get_main_queue()) {
println("little did I know")
self.incrementGame(past)
}
}
}
})
I know it is not an issue with the past.count if statement because the sell print line is not executed either. A breakpoint at the function call simply shows it skipping over however I am aware this is due to it being in an async thread.
Here is the code for runAnimations function:
func runAnimations(numberToIterate:Int, currentIteration:Int, animationsArray : [Int], completion: ((Bool) -> Void)?) {
UIView.animateWithDuration(1, animations: {
if(animationsArray[currentIteration] == 0){
self.label.text="circle!"
//self.label.alpha = 0.0
}
else if(animationsArray[currentIteration] == 1){
self.label.text="square!"
//self.label.alpha = 0.0
}
else if(animationsArray[currentIteration] == 2){
self.label.text="triangle!"
//self.label.alpha = 0.0
}
else if(animationsArray[currentIteration] == 3){
self.label.text="star!"
//self.label.alpha = 0.0
}
}, completion: {
finished in
println("BRO")
if(currentIteration+1>=numberToIterate){
self.label.alpha = 1.0
println("ook")
}
else{
println("okies")
self.runAnimations(numberToIterate, currentIteration: currentIteration+1, animationsArray: animationsArray, completion: { finished in
})
//self.runAnimations(numberToIterate, currentIteration: currentIteration+1, animationsArray: animationsArray)
}
})
The prints in runAnimation execute properly.

You actually have to call the completion block, which you haven't done by doing
completion(finished)
The completion block you defined can be seen as a separate method, which you need to call. In your case you have left your block as an optional so you must do optional checking as per the standard (completion != nil, etc)
This is a very "swift" guide on a completion block in swift, which is now called a closure. Take a look: here

Related

How to escape (to initial calling place) from a recursive function in swift?

var currentCount = 0
let totalCount = 100
func myEscapingRecursiveFunction(_ json: String, done: #escaping (Bool) -> Void) {
currentCount+=1
if currentCount == totalCount {
done(true)
}
else {
myEscapingRecursiveFunction("xyz") { done in
// what should I do here????
}
}
Calling
// (Initially called here)
myEscapingRecursiveFunction("xyz") { done in
if done {
print("completed") // I want to get response here after the recursion is finished
}
}
I want my function to escape only when the current count is equal to total count, otherwise it should recurse, the problem is that I want to get response in place where it was initially called, but it will always execute the completion handler code where it was last called. here:
You just need to pass the same escaping block to your recurse function.
so call your function like this.
myEscapingRecursiveFunction("xyz", done: done)

iOS baresip with SIP Calling

I am trying to develop an application which provides Audio and Video calling, Now I am following baresip library for the same.
and I wrote following code on button Click :
#IBAction func btnCallClick(_ sender: Any) {
guard libre_init() == 0 else { return }
// Initialize dynamic modules.
mod_init()
// Make configure file.
if let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first {
conf_path_set(path)
}
guard conf_configure() == 0 else { return }
// Initialize the SIP stack.
guard baresip_init(conf_config(), 0) == 0 else { return }
guard ua_init("SIP", 1, 1, 1, 0) == 0 else { return }
// Load modules.
guard conf_modules() == 0 else { return }
let addr = "sip:101#xxx.xxx.com:port;auth_pass=aaaa;transport=udp;answermode=auto"
// Start user agent.
guard ua_alloc(&agent, addr) == 0 else { return }
// Make an outgoing call.
guard ua_connect(agent, nil, nil, "sip:100#xxx.xxx.com", VIDMODE_OFF) == 0 else { return }
// Start the main loop.
re_main(nil)
}
Now, I am getting a call from one device to another device but it hangs my view, Why it's hanging view? I spent lots of time, anyone can help me?
I think the real problem is your re_main() function on the last line of the function. It is starting the loop execution of the thread. so untill an unless you call the re_cancel() function your execution of the process will remain in the thread.
Solution:
Putting your re_main() function on user initiated global thread will solve your problem. it will start all another process on user initiated global queue and the main thread will be free for your UI Interaction purpose.
DispatchQueue.global(qos: .userInitiated).async {
re_main(nil)
}

XCTWaiter.wait() timeout seems to take longer sometimes

To add delays in my tests I implemented this:
func execute(after: TimeInterval, testBlock: () -> Void) {
let result = XCTWaiter.wait(for: [expectation(description: "Delayed Test")], timeout: after)
if result == XCTWaiter.Result.timedOut {
testBlock()
} else {
XCTFail("Delay interrupted.")
}
}
Then I wrote a test:
func testExecute() {
var i = 1
DispatchQueue.main.asyncAfter(deadline: .now() + 0.40) {
i = 2
}
execute(after: 0.20) {
XCTAssert(i == 1)
}
execute(after: 0.15) {
XCTAssert(i == 1) // Fails once every three or four runs.
}
execute(after: 0.06) { // Never fails.
XCTAssert(i == 2)
}
}
Why does this second XCTAssert() fail regularly?
This is the only thing running on my simulator. You'd expect some jitter, but shouldn't that stay with 1 or 2 times the system clock period of 1/60s?
It turns out that delays may take up to considerably longer (up to 200ms in this 2011 experiment: http://atastypixel.com/blog/experiments-with-precise-timing-in-ios/).
Must take sufficient margins when using this execute(after:testBlock:) function.

How repeat part of function Swift

still learning the basics. I have a function in which there is a block, that needs to be repeated without calling the whole function again. How is this done in Swift?
func connected(to peripheral: Peripheral) {
let cwConnection = CWStatusBarNotification()
cwConnection.display(withMessage: "Ring Connected", forDuration: 3)
BluejayManager.shared.getHeliosInfo { (success) in
if success {
// Go on
} else {
// Repeat this block (BluejayManager.shared.getHeliosInfo)
}
}
}
Hey Riyan it's just simple. Here is the solution to your problem. Just put the block in other small method and when you just need to call that block call that small function.
func connected(to peripheral: Peripheral) {
let cwConnection = CWStatusBarNotification()
cwConnection.display(withMessage: "Ring Connected", forDuration: 3)
self.callBluejayManagerShared() // Call of block from method
}
func callBluejayManagerShared(){
BluejayManager.shared.getHeliosInfo { (success) in
if success {
// Go on
} else {
// Repeat this block (BluejayManager.shared.getHeliosInfo)
self.callBluejayManagerShared()
}
}
}
Now when you just want to call block you just need to call self.callBluejayManagerShared() method.
Hope this help you
You can use repeat - while around and BluejayManager.shared.getHeliosInfo check for success as break condition:
repeatGetInfo: repeat {
BluejayManager.shared.getHeliosInfo
{ (success) in
if success
{
// do your stuff.
break repeatGetInfo
} else
{
continue repeatGetInfo
}
}
} while true
Hope this helps

Can't perform action in background and update progressView in mainThread

I've this method :
func stepThree() {
operation = "prDatas"
let entries = self.data.componentsSeparatedByString("|***|")
total = entries.count
for entry in entries {
++current
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {
self.registerDB(entry)
})
}
status.setProgress(Float(current/total), animated: true)
finishAll()
}
I want to perform registerDB function and update my progressBar when complete.
I tested several way but never succeed
EDIT 1
Implementing #Russell proposition, work perfectly, but calculating value inside dispatch_async block always result to 0
Is there an issue about operations and multithread ?
method :
func stepThree() {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
var current = 0
var total = 0
self.operation = "prDatas"
let entries = self.data.componentsSeparatedByString("|***|")
total = entries.count
for entry in entries {
++current
self.registerDB(entry)
dispatch_async(dispatch_get_main_queue(), {
print("value of 'current' is :" + String(current))
print("value of 'total' is :" + String(total))
print("Result is : " + String(Float(current/total)))
self.updateV(Float(current/total))
})
}
})
}
Console output :
value of 'current' is :71
value of 'total' is :1328
Result is : 0.0
Your code will update the status bar immediately - so the job will not have finished.
You need to move the update so that it actually follows the registerDB function, and then you have to make the call on the main thread. Here's an example - using dummy functions instead of your function calls, so that I can ensure it works as expected
func stepThree()
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
let total = 5 // test data for demo
for entry in 0...total
{
// dummy function - just pause
sleep(1)
//self.registerDB(entry)
// make UI update on main queue
dispatch_async(dispatch_get_main_queue(),
{
self.setProgress(Float(entry)/Float(total))
})
}
})
}
func setProgress(progress : Float)
{
progressView.progress = progress
lblProgress.text = String(format: "%0.2f", progress)
}

Resources