SwiftSpinner in initial load is not working - ios

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

Related

UINavigationController return nil Swift

When i try print(self.navigationController) in viewWillApear or viewDidLoad all ok. But when delegate return response from API print(self.navigationController) return nil. What could it be?
extension EnterpriseList: APIDataDelegate {
func successRequest() { //print(self.navigtionController) == nil
DispatchQueue.main.async {
self.navigationController?.popToRootViewController(animated: true)
}
}
func badRequest() {
DispatchQueue.main.async {
Alert.showWarningAlert(withTitle: "Внимание!", andMessage: "Ошибка получения данных, попробуйте чуть позже", whereSender: self)
}
}
}
class EnterpriseList: UIViewController {
let dataSource = DataSource()
override func viewDidLoad() {
super.viewDidLoad()
dataSource.delegate = self
dataSource.makeAPICall()
}
}
extension EnterpriseList: APIDataDelegate {
func successRequest() {
DispatchQueue.main.async {
self.navigationController!.popToRootViewController(animated: true)
}
}
func badRequest() {
DispatchQueue.main.async {
}
}
}
protocol APIDataDelegate: class {
func successRequest()
func badRequest()
}
class DataSource {
var delegate: APIDataDelegate?
private let queue = DispatchQueue(label: "Test", qos: .background, attributes: [], autoreleaseFrequency: .inherit, target: nil)
func makeAPICall() {
queue.asyncAfter(deadline: .now() + 2) {[weak self] in
self?.delegate?.successRequest()
}
queue.asyncAfter(deadline: .now() + 10) {[weak self] in
self?.delegate?.successRequest()
}
}
}
The crash is because you are calling the method on deallocated object.
Here is how to fix this:
Make your delegate is weak and you are correctly deallocating the objects
weak var delegate: APIDataDelegate?
Thx #Manoj for answers it's halped me. But i found solution in other. Besides SurveyList i have UserMenu where i create static let view controllers. Removing static i solved my problem.

Swift main loop for updating a view

I'm new to Swift and trying to implement a simple test Single-View app: Upon running, it should keep appending text lines in a UITextView automatically.
However, all I get is a blank screen with the following code:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var m_logView: UITextView!
private let m_log = Log()
override func viewDidLoad() {
super.viewDidLoad()
addLog(msg: "Hello World!")
while true {
m_log.requestLog{ [weak self] (data: String) in
self?.consumeLog(log: data)
}
}
}
func consumeLog(log: String) {
addLog(msg: log)
}
func addLog(msg: String) {
m_logView.text += msg + "\n"
}
}
class Log {
func requestLog(consume: (_ log: String) -> Void) {
let log = "Data from wherever"
consume(log)
}
}
I suspected that I'm trying to update the UITextView at a wrong place. The above code simply blocks the viewDidLoad() from completing itself and showing the UITextView.
So I found viewDidAppear, but this time it gets stuck there and shows only "Hello World!" in the view.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var m_logView: UITextView!
private let m_log = Log()
override func viewDidLoad() {
super.viewDidLoad()
addLog(msg: "Hello World!")
}
override func viewDidAppear(_ animated: Bool) {
while true {
m_log.requestLog{ [weak self] (data: String) in
self?.consumeLog(log: data)
}
}
}
func consumeLog(log: String) {
addLog(msg: log)
}
func addLog(msg: String) {
m_logView.text += msg + "\n"
}
}
class Log {
func requestLog(consume: (_ log: String) -> Void) {
let log = "Data from wherever"
consume(log)
}
}
Most iOS MVC tutorials I found teach how to implement the user interactions, but stay away from how to update the view by programmtically changing the model from the backend.
I'm probably looking for a callback/delegate where I can refresh UITextView linked with its data model whenever the data changes, but where is it?
The while loop is completely inappropriate because it causes a deadlock.
Use a Timer which works asynchronously
Replace
while true {
m_log.requestLog{ [weak self] (data: String) in
self?.consumeLog(log: data)
}
}
with
Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true) { [weak self] _ in
m_log.requestLog{ data in
self?.consumeLog(log: data)
}
}
And you might update the UI explicitly on the main thread
func addLog(msg: String) {
DispatchQueue.main.async {
m_logView.text += msg + "\n"
}
}
Note:
According to the Swift naming convention name variables lowerCamelCased for example mLogView

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

wait for two asynchronous completion functions to finish, before executing next line code

I have two functions: func Females_NonChat() and func males_NonChat()
I want to wait for both of them to finish before executing the print statement in viewdidload. Do I need another completion handler to accomplish that?
Those functions used are firebase completion handlers for requesting information from the online database...
override func viewDidLoad() {
super.viewDidLoad()
func Females_NonChat()
func males_NonChat()
print("finished executing both asynchronous functions")
}
func Females_NonChat(){
Anon_Ref.child("Chatting").child("female").observeSingleEventOfType(.Value, withBlock: {(snapshot) in
if let FemInChatting = snapshot.value as? [String : String] {
print("executing")
}
})
}
func males_NonChat(){
Anon_Ref.child("Chatting").child("male").observeSingleEventOfType(.Value, withBlock: {(snapshot) in
print("executing")
})
}
Generally you'd use a dispatch group, enter the group before each asynchronous method, leave the group upon completion of each asynchronous method, and then set up a group notification when all "enter" calls are matched by corresponding "leave" calls:
override func viewDidLoad() {
super.viewDidLoad()
let group = dispatch_group_create()
dispatch_group_enter(group)
Females_NonChat() {
dispatch_group_leave(group)
}
dispatch_group_enter(group)
males_NonChat() {
dispatch_group_leave(group)
}
dispatch_group_notify(group, dispatch_get_main_queue()) {
print("finished executing both asynchronous functions")
}
}
func Females_NonChat(completionHandler: () -> ()) {
Anon_Ref.child("Chatting").child("female").observeSingleEventOfType(.Value) { snapshot in
if let FemInChatting = snapshot.value as? [String : String] {
print("executing")
}
completionHandler()
}
}
func males_NonChat(completionHandler: () -> ()) {
Anon_Ref.child("Chatting").child("male").observeSingleEventOfType(.Value) { snapshot in
print("executing")
completionHandler()
}
}
Here's an example that executes two async methods and prints when both are finished.
Try copying this code into a Swift Playground and running it.
import Foundation
func doTwoThings() {
var thing1Done: Bool = false
var thing2Done: Bool = false
func done() {
if thing1Done && thing2Done {
print("Both things done! at \(getTime())")
}
}
doThing1(completionHandler: {
thing1Done = true
done()
})
doThing2(completionHandler: {
thing2Done = true
done()
})
}
func doThing1(completionHandler: #escaping () -> Void) {
print("Starting Thing 1 at \(getTime())")
Timer.scheduledTimer(withTimeInterval: 3, repeats: false, block: {_ in
print("Done with Thing 1 at \(getTime())")
return completionHandler()
})
}
func doThing2(completionHandler: #escaping () -> Void) {
print("Starting Thing 2 at \(getTime())")
Timer.scheduledTimer(withTimeInterval: 5, repeats: false, block: {_ in
print("Done with Thing 2 at \(getTime())")
return completionHandler()
})
}
func getTime() -> String {
let date = Date()
let calendar = Calendar.current
let hour = calendar.component(.hour, from: date)
let minute = calendar.component(.minute, from: date)
let second = calendar.component(.second, from: date)
return "\(hour):\(minute):\(second)"
}
doTwoThings()
Output:
Starting Thing 1 at 11:48:51
Starting Thing 2 at 11:48:51
Done with Thing 1 at 11:48:54
Done with Thing 2 at 11:48:56
Both things done! at 11:48:56

Do one action when method is finished in Swift

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()
}
}

Resources