How to execute the further code only after the successful JSON response? - ios

I am very beginner in swift and I am trying to fetch some JSON Data from an api and then creating an array from that Data.
Alamofire.request(.GET, URL)
.responseJSON
{
response in
let JSON = response.result.value
let response = JSON as! NSDictionary
let Data = response.objectForKey("data")!
for slot in timeSlot as! NSDictionary
{
let json = slot.value
let availability = json as! NSDictionary
let myavailable = availability.objectForKey("available")!
let slotTime = availability.objectForKey("time")!
if (myavailable as! NSNumber == 1)
{
self.fetchSlot.append(slotTime as! String)
}
}
for x in self.mySlot
{
for c in self.fetchSlot
{
if (c == x)
{
self.availableSlot.append(x)
}
}
}
}
Now I am trying to print the "self.availableslot" in the same viewDid load function.
But it always returning an empty array, because it is compiling before all the JSON data is fetched.
Please if there is any way how can I use reload method or completion handler kind of things to get my job done.

func performAlamoFireRequest(completion: () -> Void) {
Alamofire.request(.GET, URL).responseJSON {
response in
let JSON = response.result.value
let response = JSON as! NSDictionary
let Data = response.objectForKey("data")!
for slot in timeSlot as! NSDictionary {
let json = slot.value
let availability = json as! NSDictionary
let myavailable = availability.objectForKey("available")!
let slotTime = availability.objectForKey("time")!
if (myavailable as! NSNumber == 1) {
self.fetchSlot.append(slotTime as! String)
}
}
for x in self.mySlot {
for c in self.fetchSlot {
if (c == x) {
self.availableSlot.append(x)
}
}
}
completion()
}
}
performAlamoFireRequest() {
//code to perform after here
}

Related

How to convert array of NSCFString to Array of NSCFNumber in swift?

I have fetched array (say contactNameList) from SQLITE which is array of NSCFString. I want to compare objects of contactNameList with array of Id(say bookIdArray) which is of Int type.Can anyone please guide me.
Help will be appreciated.Thank you in advance :)
Code:
let testDetail_Obj = OfflineDB()
ContactDataArray = testDetail_Obj.fetch_BooksFromSQLite()
for i in 0..< ContactDataArray.count
{
let newItem: Any = ContactDataArray[i] as Any
contactNameList.addObjects(from: [(newItem as AnyObject).value(forKey: "book_Id") as Any])
print("contactNameList fetched from db = \(contactNameList)")
}
bookIdArray = contactNameList // tried this
func loadBooks() {
let v = Constant.DBHandler()
v.clearDatabase()
Alamofire.request(Constant.url.getAllBooksUrl, method: .get, parameters: nil, encoding: JSONEncoding.default)
.downloadProgress(queue: DispatchQueue.global(qos: .utility)) { progress in
}
.validate { request, response, data in
// Custom evaluation closure now includes data (allows you to parse data to dig out error messages if necessary)
return .success
}
.responseJSON {
response in switch response.result {
case .success(let JSON):
if let jsonResult = JSON as? Dictionary<String, AnyObject> {
// do whatever with jsonResult
let booksJson = jsonResult ["objects"]
print("jsonResult In loadBook= \(jsonResult)")
let realm = try! Realm()
for bookJson in booksJson as! [NSDictionary] {
let book = Book()
print(bookJson)
book.author = bookJson["author"] as! String
print("\(String(describing: jsonResult ["author"]))")
book.bookImg = bookJson["book_img"] as! String
book.bookName = bookJson["book_name"] as! String
book.desc = bookJson["description"] as! String
book.language = bookJson["language"] as! String
book.noOfChapters = bookJson["no_of_chapters"] as! Int
book.id = bookJson["id"] as! Int
book.timestamp = bookJson["timestamp"] as! String
if bookIdArray.contains(book.id) {
// where, static var bookIdArray = [2,10]
book.isHidden = false
}}}}}}
I want to show i.e -> book.isHidden = false , for all books whose id is present in contactNameList.I have tried
bookIdArray = contactNameList
But not getting output as per requirement.

Synchronized code in iOS/Swift [duplicate]

This question already has answers here:
How to return value from Alamofire
(5 answers)
Closed 5 years ago.
I am new with iOS programming. I am trying to make a piece of code in my function be synchronized, but it doesn't seem to work:
func fetchLocationsList(searchText:String)->Array<String> {
print ("searched text:\(searchText)")
let url = URL(string:"http://api.openweathermap.org/data/2.5/find?q=\(searchText)&type=like&sort=name&cnt=9&APPID=a33aa72")
//Using Alamofire to handle http requests
Alamofire.request(url!).responseJSON {response in
guard let jsonResponse = response.result.value as? [String:Any]
else { print ("error in json response")
return}
guard let list = jsonResponse["list"] as? NSArray else {return}
let lockQueue = DispatchQueue(label:"Et.My-Weather-App.queue1")
_ = lockQueue.sync{
for index in 0..<list.count {
print ("index is: \(index)")
guard let listElement = list[index] as? [String:Any] else {return}
let id = listElement["id"] as! Int
print ("id is: \(id)")
let cityName = listElement["name"] as! String
print ("cityName is: \(cityName)")
let sys = listElement["sys"] as! [String:Any]
let country = sys["country"] as! String
print ("country is: \(country)")
let element = "\(cityName), \(country), \(id)"
print ("\(element)")
self.resultsArray.append(element)
}
}
}
if self.resultsArray.count==0 {
print ("results array is also zero!")
}
return self.resultsArray
}
When I run it, I see that the line "results array is also zero!" is printed before the "for" loop fills the resultArray with elements, so the returned resultArray is always empty!
What am I doing wrong?
I suggest you do this as async tasks are a pain and this works quite well.
func fetchLocationsList(searchText:String, completion: #escaping (_ results:Array<String>)->()){
print ("searched text:\(searchText)")
let url = URL(string:"http://api.openweathermap.org/data/2.5/find?q=\(searchText)&type=like&sort=name&cnt=9&APPID=a33aa72")
//Using Alamofire to handle http requests
Alamofire.request(url!).responseJSON {response in
guard let jsonResponse = response.result.value as? [String:Any] else { print ("error in json response"); return}
guard let list = jsonResponse["list"] as? Array<Dictionary<String,Any>> else { return }
var array = Array<String>() // create an array to store results.
for item in list {
let id = item["id"] as! Int
let cityName = item["name"] as! String
let sys = item["sys"] as! Dictionary<String,Any>
let country = sys["country"] as! String
let element = "\(cityName), \(country), \(id)"
array.append(element) // add to that array.
}
completion(array) //send the array via the completions handler.
}
}
So in your viewDidLoad or whatever.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
fetchLocationsList(searchText: "Whatever this string is") { (results) in
self.resultsArray.append(contentsOf: results)
// Then do anything else you need to do after this function has completed within this closure.
}
}

iOS Swift App, Openweather API

I'm making a weather app using OpenweatherAPI. I download data from web, but when I want to pass it to another class it show as nil. Here is the code:
So that's the class I'm getting data from the API
var currentTemp: Double {
if _currentTemp == nil {
_currentTemp = 120.0
}
return _currentTemp
}
func downloadWeatherDetails(completed: #escaping DownloadComplete) {
Alamofire.request(CURRENT_WEATHER_URL).responseJSON { response in
let result = response.result
if let dict = result.value as? Dictionary<String, Any> {
if let main = dict["main"] as? Dictionary<String, Any> {
if let currentTemperature = main["temp"] as? double_t {
let kelvinToCelsiusPreDivision = (currentTemperature - 273.15)
let kelvinToCelsius = Double(round((10 * kelvinToCelsiusPreDivision) / 10))
self._currentTemp = kelvinToCelsius
print(self._currentTemp)
}
}
}
completed()
} }
And the mainVC - ViewController:
func updateMainUI() {
currentTempLabel.text = "\(currentWeather.currentTemp)"
}
I'm of course calling updateMainUI in ViewDidLoad, but IMHO I think the method that updates UI is probably called before getting the data from the JSON.
The Label on the App shows 120 - so it is considered as nil...
Sorry about parenthesis if there is something wrong.
Thanks for help in advice :)
EDIT:
Ohh and I forgot to add.. The data from API is perfectly fine, so the call to API is working :)
// I Hope that helps
func downloadWeatherDetails(completed: #escaping DownloadComplete) {
//Download Current Weather Data
Alamofire.request(CURRENT_WEATHER_URL).responseJSON { response in
let result = response.result
if let dict = result.value as? Dictionary<String, AnyObject> {
if let main = dict["main"] as? Dictionary<String, AnyObject> {
if let currentTemperature = main["temp"] as? Double {
let kelvinToFarenheitPreDivision = (currentTemperature * (9/5) - 459.67)
let kelvinToFarenheit = Double(round(10 * kelvinToFarenheitPreDivision/10))
self._currentTemp = kelvinToFarenheit
print(self._currentTemp)
}
}
}
completed()
}
}

How to populate my tableview with a mutablearray from json

So I'm fetching data from a url which is in a json format. I'm trying to display the data in my tableview but, even though it feels simple, I can't figure out how to do it.
class CompanyModel {
func getJSON() {
let companyArray: NSMutableArray = NSMutableArray()
let requestURL: NSURL = NSURL(string: "http://localhost/Companies/JSON.php")!
let urlRequest: NSMutableURLRequest = NSMutableURLRequest(URL: requestURL)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(urlRequest) {
(data, response, error) -> Void in
let httpResponse = response as! NSHTTPURLResponse
let statusCode = httpResponse.statusCode
if (statusCode == 200) {
print("Everyone is fine, file downloaded successfully.")
do{
let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)
if let companies = json["companies"] as? [[String: AnyObject]] {
for company in companies {
if let name = company["name"] as? String,
let phoneNumber = company["phone_number"] as? String,
let website = company["website"] as? String,
let email = company["email"] as? String,
let address = company["address"] as? String
{
let company = CompanyModel()
company.name = name
company.phoneNumber = phoneNumber
company.website = website
company.email = email
company.address = address
}
companyArray.addObject(company)
print(companyArray)
}
}
} catch {
print("Error with Json: \(error)")
}
}
print(companyArray) <- array is populated
}
print(companyArray) <- array is empty
task.resume()
}
}
I know i've done it before....I'm guessing in viewDidLoad() I'd call CompanyModel().getJSON() which would fetch the data, then store it in an empty array but my mind feels blank on how to do it.
I can't declare a variable of NSarray and store the data of it the variable directly for me to then populate the tableview. Nevertheless, I hope this explains what I'm trying to acheive.
Well first change the function to return your company array :
func getJSON() -> NSMutableArray {
}
By the end of the for loop return the company array
for company in companies {
}
After your array is populated, return the array inside this block:
dispatch_async(dispatch_get_main_queue(), {
return companyArray
})
And after task.resume() return the array:
return companyArray
From anywhere you wanna call this class and get the array :
Get a reference of the class
Let companyModal = CompanyModel()
And in anywhere you have your table view and the class let's say in viewDidLoad, you should first have NSMutableArray.
var arraySource = NSMutableArray()
And in viewDidLoad :
arraySource = companyModal.getJSON()
And to show the data in tableView do :
Mytableview.reloadData()
You can't use return within the closure of an asynchronous network request, you have to use a callback instead.
You need a NSMutableArray from the request, so first, let's make a callback for this:
completion: (array: NSMutableArray)->()
We add this callback to the method signature:
func getJSON(completion: (array: NSMutableArray)->())
And then at the location where the array will be available, we place this completion handler:
class CompanyModel {
func getJSON(completion: (array: NSMutableArray)->()) {
let companyArray: NSMutableArray = NSMutableArray()
let requestURL: NSURL = NSURL(string: "http://localhost/Companies/JSON.php")!
let urlRequest: NSMutableURLRequest = NSMutableURLRequest(URL: requestURL)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(urlRequest) {
(data, response, error) -> Void in
let httpResponse = response as! NSHTTPURLResponse
let statusCode = httpResponse.statusCode
if (statusCode == 200) {
do{
let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)
if let companies = json["companies"] as? [[String: AnyObject]] {
for company in companies {
if let name = company["name"] as? String,
let phoneNumber = company["phone_number"] as? String,
let website = company["website"] as? String,
let email = company["email"] as? String,
let address = company["address"] as? String {
let company = CompanyModel()
company.name = name
company.phoneNumber = phoneNumber
company.website = website
company.email = email
company.address = address
companyArray.addObject(company)
}
}
// CALLBACK HERE
completion(array: companyArray)
}
} catch {
print("Error with Json: \(error)")
}
}
}
task.resume()
}
}
Now to get the array from the network we use a trailing closure like this:
getJSON { (array) in
print(array)
}

Parse JSON Swift TableView

I'd like to extract "Event", "Hasta" & "Location" from this JSON URL (https://www.kimonolabs.com/api/7flcy3qm?apikey=gNq3hB1j0NtBdAvXJLEFx8JaqtDG8y6Y), but I'm struggling with how to do it? Can anyone help me? Here's my code... I'd like to then populate a tableview with these 3.
override func viewDidLoad() {
super.viewDidLoad()
splitViewController!.preferredDisplayMode = UISplitViewControllerDisplayMode.AllVisible
UINavigationBar.appearance().barTintColor = UIColor(red: 52.0/255.0, green: 170.0/255.0, blue: 220.0/255.0, alpha: 1.0)
UINavigationBar.appearance().tintColor = UIColor.whiteColor()
UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName : UIColor.whiteColor()]
let url = NSURL(string:"https://www.kimonolabs.com/api/7flcy3qm?apikey=gNq3hB1j0NtBdAvXJLEFx8JaqtDG8y6Y")!
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url) { (data, response, error) -> Void in
if error != nil {
print(error)
} else {
if let data = data {
do {
let jsonResult = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary
if jsonResult!.count > 0 {
if let results = jsonResult!["results"] as? NSDictionary, collection2 = results["collection2"] as? NSArray {
for entry in collection2 {
if let dict = entry["Event"] as? NSDictionary {
print(dict)
}
else if let array = entry as? NSArray {
} else {
}
}
if let items = jsonResult?["Date"] as? NSArray {
print(items)
}
}
}
} catch {
print("In catch block")
}
}
}
}
task.resume()
}
Parsing JSON with Swift is hell. You can do that easily with SwiftyJSON.
With your JSON:
// Get content of json url
let jsonString = try NSString.init(contentsOfURL: url!, encoding: NSUTF8StringEncoding)
// Create JSON object from data
let json = JSON(data: jsonString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!)
// Check if array for key "collection2" exists
if let collection2 = json["results"]["collection2"].array {
// Create JSON array from it and loop for each object
for (key, subJson):(String, JSON) in JSON(collection2) {
// Check if dictionary for key "Event" exists
if let event = subJson["Event"].dictionary {
print(event)
}
// Check if string for key "Hasta" exists
if let hasta = subJson["Hasta"].string {
print(hasta)
}
// Check if string for key "Location" exists
if let location = subJson["Location"].string {
print(location)
}
}
}
I created this online utility (http://www.json4swift.com) that transforms your json into swift representable models that you can manipulate as easily as this:
// Get content of json url
let jsonString = try NSString.init(contentsOfURL: url!, encoding: NSUTF8StringEncoding)
// Create JSON Dictionary from data
var jsonResult = NSJSONSerialization.JSONObjectWithData(jsonString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, options: NSJSONReadingOptions.MutableContainers, error: &err) as NSDictionary
//Create instance for base model representation
let responseModel = Json4Swift_Base(dictionary: jsonResult)
//print name
print(responseModel!.name)
//Get the collection2 from result
let collection2 = responseModel?.results!.collection2
//Get the first object from collection 2
let firstObject = collection2?.first
//Print the event and hesta
print(firstObject?.event?.text)
print(firstObject?.hasta)
In case of a tableview, you'll implement the delegate method cellForRowAtIndexPath
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("YourCellIdentifier")
if cell == nil {
cell = UITableViewCell()
}
//Assuming you have responseModel instantiated earlier
let collection2 = responseModel?.results!.collection2!
//Get the n'th object from collection 2
let object = collection2[indexPath.row]
//Populate the cell the event and hesta
cell.textLabel?.text = object?.event?.text
cell.detailTextLabel?.text = object?.hasta
return cell
}
Disclaimer: Consider the above as more of a pseudo-code, not actually tested but gives you the idea about the handling.

Resources