Do one action when method is finished in Swift - ios

I want do one action when one method is finished, I execute one method in other method and I want the second method stop until the first method is finished.
I have that method:
func ejecutarOBJC(){
let txtNombre = self.view.viewWithTag(4) as? UITextField
let textoNombre=txtNombre?.text
let txtContra = self.view.viewWithTag(5) as? UITextField
let textoContra=txtContra?.text
let instanceOfCustomObject: SQLViewController = SQLViewController()
instanceOfCustomObject.nombre = textoNombre;
instanceOfCustomObject.contra = textoContra;
instanceOfCustomObject.obtenerExistenciaUsuario()
}
And also the other method:
func otherMethod(){
ejecutarOBJC()
//I want continue with that method when the execution of the other method finish
}

This is how you would achieve this:
func methodOne() {
//Method one code here
methodTwo()
}
func methodTwo() {
//Method Two code here.
}
As per your comment, here is how to wait when using async code:
func methodOne() {
//Code goes here
methodTwo { () -> () in
//Method two has finished
}
}
func methodTwo(completion: () -> ()) {
//Code goes here
completion()
}

Use closures:
func callCompetionFunction()
{
// Tira mola meseda (do your stuff)
completionFunction("a parameter") { () -> Void in
print("function copleted")
}
}
func completionFunction(param: AnyObject, completion: ()->Void)
{
// Do your stuff
completion()
}
To test it in a view controller
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
callCompetionFunction()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func callCompetionFunction()
{
// Tira mola meseda (do your stuff)
print("do something here")
completionFunction("a parameter") { () -> Void in
print("function copleted")
}
}
func completionFunction(param: AnyObject, completion: ()->Void)
{
// Do your stuff
if param is String
{
print("parameter = \(param)")
}
print("going to execute completion closure")
completion()
}
}

Related

Protocol-Delegate pattern not notifying View Controller

My Model saves data to Firestore. Once that data is saved, I'd like it to alert my ViewController so that a function can be called. However, nothing is being passed to my ViewController.
This is my Model:
protocol ProtocolModel {
func wasDataSavedSuccessfully(dataSavedSuccessfully:Bool)
}
class Model {
var delegate:ProtocolModel?
func createUserAddedRecipe(
docId:String,
completion: #escaping (Recipe?) -> Void) {
let db = Firestore.firestore()
do {
try db.collection("userFavourites").document(currentUserId).collection("userRecipes").document(docId).setData(from: recipe) { (error) in
print("Data Saved Successfully") // THIS OUTPUTS TO THE CONSOLE
// Notify delegate that data was saved to Firestore
self.delegate?.wasDataSavedSuccessfully(dataSavedSuccessfully: true)
}
}
catch {
print("Error \(error)")
}
}
}
The print("Data Saved Successfully") outputs to the console, but the delegate method right below it doesn't get called.
And this is my ViewController:
class ViewController: UIViewController {
private var model = Model()
override func viewDidLoad() {
super.viewDidLoad()
model.delegate = self
}
}
extension ViewController: ProtocolModel {
func wasDataSavedSuccessfully(dataSavedSuccessfully: Bool) {
if dataSavedSuccessfully == true {
print("Result is true.")
}
else {
print("Result is false.")
}
print("Protocol-Delegate Pattern Works")
}
}
Is there something I'm missing from this pattern? I haven't been able to notice anything different in the articles I've reviewed.
So I test your code and simulate something like that
import UIKit
protocol ProtocolModel {
func wasDataSavedSuccessfully(dataSavedSuccessfully:Bool)
}
class Model {
var delegate:ProtocolModel?
// I use this timer for simulate that firebase store data every 3 seconds for example
var timer: Timer?
func createUserAddedRecipe(
docId:String) {
timer = Timer.scheduledTimer(withTimeInterval: 3, repeats: true, block: { _ in
self.delegate?.wasDataSavedSuccessfully(dataSavedSuccessfully: true)
})
}
}
class NavigationController: UINavigationController {
var model = Model()
override func viewDidLoad() {
super.viewDidLoad()
model.delegate = self
// Call this method to register for network notification
model.createUserAddedRecipe(docId: "exampleId")
}
}
extension NavigationController: ProtocolModel {
func wasDataSavedSuccessfully(dataSavedSuccessfully: Bool) {
print(#function)
}
}
so you can see the result as image below, my delegate update controller that conform to that protocol.

swift set crash in asynchous queue

I found the weird crash when using Set in async queue closure below, confirmed that it only happens in async queue, but Array works.
func testA1() {
var set = Set<Int>()
for i in 0...10 {
DispatchQueue.global().async {
set.update(with: i) // Crash here: EXC_BAD_ACCESS
// set.insert(i)
}
}
print(set as Any)
}
func testA2() {
var set = Set<Int>()
for i in 0...10 {
DispatchQueue.global().sync {
set.update(with: i) // Works!
}
}
print(set as Any)
}
func testB() {
var array = [Int]() // Works!
for i in 0...10 {
DispatchQueue.global().async {
array.append(i)
}
}
print(array as Any)
}
Swift version:
Apple Swift version 5.3.2 (swiftlang-1200.0.45 clang-1200.0.32.28)
Target: x86_64-apple-darwin20.2.0
My bad or swift bug? Why?
Most of datatypes in Swift aren't thread-safe.
You should interact using different ways.
protocol ThreadSafeExecutor {
var semaphore: DispatchSemaphore { get set }
func wait()
func signal()
}
extension ThreadSafeExecutor {
func wait() {
semaphore.wait()
}
func signal() {
semaphore.signal()
}
}
class YourClass: ThreadSafeExecutor {
func someMethod() {
wait()
defer {
signal()
}
/// thread-safe code
}
}

SwiftSpinner in initial load is not working

Upon calling SwiftSpinner, on viewDidLoad , Swift spinner is not working
Please find below the code i am using,
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.global(qos: .background).async {
self.basicSync {(isSynced) in
DispatchQueue.main.async {
SwiftSpinner.hide()
}
}
}
DispatchQueue.main.async {
SwiftSpinner.show("Syncing")
}
}
public func basicSync(completion: #escaping (Bool) -> ()) {
//Sync related work
completion("true")
}
I am not able to find a way to call Swift spinner on initial load
Some of the methods i tried with SwiftSpinner.Show from above code
To call,
SwiftSpinner.show("Syncing")
To call it main inside main thread
DispatchQueue.main.async {
DispatchQueue.main.async {
SwiftSpinner.show("Syncing")
}
}
I was able to achieve it when it is written like this,
DispatchQueue.main.async {
DispatchQueue.main.async {
DispatchQueue.main.async {
SwiftSpinner.show("Syncing")
}
}
}
But I dont think it is the correct coding standard, new to Swift and coding technology
I have this issue before, you need to do the following
func delay(seconds: Double, completion: #escaping () -> ()) {
let popTime = DispatchTime.now() + Double(Int64( Double(NSEC_PER_SEC) * seconds )) / Double(NSEC_PER_SEC)
DispatchQueue.main.asyncAfter(deadline: popTime) {
completion()
}
}
then in view did load
override func viewDidLoad() {
super.viewDidLoad()
delay(seconds: 0.5) {
SwiftSpinner.show("Syncing")
}
}
That's it :D
Try adding it in
viewdidappear

Why doesn't my completion block work?

Implementing solution given here How to make a synchronous request using Alamofire?
I don't get any errors, it just doesn't work as expected. In tableViewController
override func viewDidLoad() {
super.viewDidLoad()
loadData() { (didCompleteRequest) in
if (didCompleteRequest) {
self.TodosTableView.delegate = self
self.TodosTableView.dataSource = self
print("loading successfull")
} else {
print("loading failed")
}
}
print("leaving viewDidLoad")
}
func loadData(completion: #escaping (Bool) -> Void) {
Alamofire.request(TodosViewController.serverAdress + "projects/index.json").responseJSON { response in
do {
// async stuff
} catch {
completion(false)
}
print("leaving loadData")
completion(true)
}
}
output I get
leaving viewDidLoad
leaving loadData
loading successfull
apparently, the first element should be the last one
First viewDidLoad is running in the main thread. So when you put this loadData() in viewDidLoad controls dispatched to background thread where alamofire works on, and the main thread continues and prints leaving viewDidLoad
Try this
override func viewDidLoad() {
super.viewDidLoad()
self.TodosTableView.delegate = self
self.TodosTableView.dataSource = self
loadData() { (didCompleteRequest) in
if (didCompleteRequest) {
self.TodosTableView.reloadData()
print("loading successfull")
} else {
print("loading failed")
}
}
print("leaving viewDidLoad")
}
You are call block code after get response from server. so first call "print("leaving viewDidLoad")".
response code get with delay so call block code with delay

How to make function for HTTP request on other class in Swift?

I'm writing a app to make a http requests with SwiftHTTP, but I want to create a class to make this, and in the ViewController I call the functions to do this. So, I create a UIButton to call the functions.
I don't know if I need use threads or exists ways to make this easy.
ViewController.swift
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var button: UIButton!
#IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
button.addTarget(self,action:#selector(self.clickRequest(sender:)), for: UIControlEvents.touchUpInside )
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#objc func clickRequest (sender: UIButton) {
}
}
HTTPService.swift
import Foundation
import SwiftHTTP
class HTTPService {
}
How I make this in others Apps. But inside of ViewController.swift.
HTTP.GET("https://www.host.com/example",requestSerializer: JSONParameterSerializer()) {
response in
if let err = response.error {
print(err.localizedDescription)
return
}
} catch let err as NSError {
print(err)
}
}
Create one method with successBlock and failureBlock inside your HTTPService service class like below,
class HTTPService {
func makeRequest(params: [String: Any], successBlock: () -> Void, failureBlock: () -> Void) {
HTTP.GET("https://www.host.com/example",requestSerializer: JSONParameterSerializer()) {
response in
if let err = response.error {
print(err.localizedDescription)
failureBlock() // Call failure block
return
} else {
successBlock() // Call success block
}
} catch let err as NSError {
print(err)
failureBlock() // Call failure block
}
}
}
You can call this method like below,
#objc func clickRequest (sender: UIButton) {
HTTPService().makeRequest(params: ["name": "userName"], successBlock: {
// Handle API success here. E.g Reloading table view
}) {
// Handle API failure here. E.g Showing error to user
}
}
Thanks

Resources