I cannot access my array objects anywhere, how can I access them in swift?
Data is loaded from Firebase asynchronously. While you may store it in variables that can be accessed from anywhere, the timing matters.
In your code, when the print(self.arr)
runs, the self.arr.append(...)
hasn't run yet. You can most easily see this by placing breakpoints on these lines and running the code in a debugger, or by placing some logging code and checking its output.
For this reason, all code that needs data from the database needs to be inside the completion handler or be called from there.
For some more on this, and examples of solutions, see:
- Code not finishing the function, it is ending execution halfway through, which in turn includes more links
- Make code with Firebase asynchronous
- Why isn't my function that pulls information from the database working?, which even more links
- Finish all asynchronous requests before loading data?, using a dispatch group
- Asynchronous Swift call into array
- using variables outside of completion block
- wait for two asynchronous completion functions to finish, before executing next line code
- Finish all asynchronous requests before loading data?
why I can't access my 3rd level CoreData data in swift?
The temas
property is a NSOrderedSet
, and the subscript [0]
returns the
type AnyObject
. So (as already said in a comment) you have to cast the AnyObject
to the actual type
let curso = cursos[index]
println(curso.nombre)
let firstTema = curso.temas[0] as Tema
println(firstTema.nombre)
let firstSubTema = firstTema.subTemas[0] as SubTema
println(firstSubTema.nombre)
Note that you can simplify your loop using for - in
:
for curso in cursos {
// ...
}
and recursively enumerating all objects would look like
for curso in cursos {
println(curso.nombre)
for tema in curso.temas.array as [Tema] {
println(tema.nombre)
for subtema in tema.subTemas.array as [SubTema] {
println(subtema.nombre)
}
}
}
using variables outside of completion block
The entire purpose of the completion
parameter of userBinfo
is to provide a mechanism for being informed when the asynchronous observeEventType
is called. So put code contingent upon the completion of that asynchronous method inside the userBinfo { user in ... }
closure.
And if part of the UI doesn't make sense until that asynchronous completion
closure is called, then have viewDidLoad
configure the UI to make that explicit (perhaps show a UIActivityIndicatorView
or whatever) and then remove that stuff inside the completion handler.
override func viewDidLoad() {
super.viewDidLoad()
// do whatever you want to let the user know that something asynchronous
// is happening, e.g. add a spinning `UIActivityIndicatorView` or whatever
userBinfo { user in
self.userBinfos = user
// Update the UI here, including removing anything we presented to let
// the user know that the asynchronous process was underway. If you were
// dealing with UITableView`, you'd call `tableView.reloadData()` here.
}
// but not here
}
Can't access decoded JSON data (from API) outside the URLSession data task Function Scope
As you already have a completion handler use it and pass the received data
func getJSON(completed: @escaping ([API_data]) -> Void) {
let url = "URL Here" // I have the original URL here, which I can't shar
let task = URLSession.shared.dataTask(with: URL(string: url)!) { data, _ , error in
if let error = error { print(error); return }
do {
completed(try JSONDecoder().decode([API_data].self,from:data!))
} catch{
print(error)
}
}
task.resume()
}
and use it
getJSON { apiData in
print(apiData[0].id) // This prints my data
}
Or more comfortable with the Result
type
func getJSON(completed: @escaping (Result<[API_data],Error>) -> Void) {
let url = "URL Here" // I have the original URL here, which I can't shar
let task = URLSession.shared.dataTask(with: URL(string: url)!) { data, _ , error in
if let error = error { completed(.failure(error)); return }
Result { try JSONDecoder().decode([API_data].self,from: data!) }
}
task.resume()
}
getJSON { result in
switch result {
case .success(let apiData): print(apiData[0].id) // This prints my data
case .failure(let error): print(error)
}
}
Why I can't use variable that I defined in viewDidLoad in swift 3
The issue is you cannot access instance property when you initialized another another property outside any method because complier don't know which one initialized the first, so what you need to do is declare headerList
simply set the account
string only as first object of array and latter changed it with new value.
var userAccountMoney = String()
var headerList = ["account" , "Help" , "" ]
Now in viewDidLoad
simply replace the first object with new value.
override func viewDidLoad() {
super.viewDidLoad()
let userAccount = profileViewController().userMoney
let numberFormatter = NumberFormatter()
numberFormatter.locale = Locale(identifier: "fa")
numberFormatter.numberStyle = NumberFormatter.Style.decimal
numberFormatter.string(from: NSNumber(value: userAccount))
userAccountMoney = numberFormatter.string(from: NSNumber(value: userAccount))!
self.headerList[0] = "account\(userAccountMoney)"
}
Asynchronous Swift call into array
func fetchUser(_ completion:@escaping ([noteClass] , _ success: Bool)-> Void){
let coordinotes = [noteClass]()
FIRDatabase.database().reference().child("notes").observe(.childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = noteClass(dictionary: dictionary)
coordinotes.append(user)
}
completion(coordinotes, true)
}, withCancel: nil)
}
and then you call it in viewDidLoad
like this:
fetchUser { (coordinotes, success) in
if success {
self.coordinotes = coordinote
self.loadAllCoordinotes()
}
}
Passing Data Indirectly to an Unrelated NSViewController
With the caveat that "globals and singletons should be avoided," it sounds like they are a good fit for what you're trying to do. As you get more comfortable in Cocoa you can move into more sophisticated means of accomplishing this (dependency injection). Look into this as you get more comfortable with Cocoa.
Create a simple singleton type:
// AppState.swift
class AppState {
// Basic singleton setup:
static let shared = AppState()
private init() {} // private prevents instantiating it elsewhere
// Shared state:
var carrierArray: [String] = []
}
Access it from your view controllers:
// YourViewController.swift:
@IBAction func doSomething(_ sender: Any) {
AppState.shared.carrierArray = ...
}
If you need to update the other view controllers when this shared state changes, notifications are a good tool for that. You could do this with a didSet
on carrierArray
, or simply trigger the notification manually.
Related Topics
Swift Language Multicast Delegate
Pass Data from Tableview to Tab Bar View Controller in Swift
Unrecognized Selector Sent to Instance Swift 3
How to Change the Number of Decimal Places iOS
Passing Data Between View Controllers in Swift (From Tableview to Detailviewcontroller)
How to Draw a Simple Rounded Rect in Swift (Rounded Corners)
Please Add the Host Targets for the Embedded Targets to the Podfile
Swift - Uitableview Didselectrowatindexpath & Diddeselectrowatindexpath Add & Remove Indexpath Ids
How to Send a Request with Alamofire with Xml Body
Nsexceptionallowsinsecurehttploads Not Working for Ip Addresses
iOS Development App Startup Crash
Target Is Not Found, Please Reconnect the Device, Xcode:Device Support File
How to Create an Alert in a Swift File Model That Works for Various View Controller
iOS Sharecontext Tapping on Suggestion Intent Property of Extensioncontext Is Nil
Non-Main Bundle File as Alert Sound