ios - How to wait api response using Alamofire - ios

I want to ask about Semaphore in Alamofire.
I want the app wait for data from the server return success and continue to execute the code after (synchronous type). I use semaphore, but when the api function is called, the app is suspended...
This code is call data from server:
func getAllModels() -> [String] {
var _modelList:[String] = []
let url = BASE_URL + "getAllProductAndModelv2"
let semaphore = DispatchSemaphore(value: 0)
Alamofire.request(url, method:.get, parameters: [:], encoding: JSONEncoding.default).responseJSON { response in
let data = NSData(contentsOf: URL(string: url)!)
do {
if let data = data, let json = try JSONSerialization.jsonObject(with: data as Data) as? [String: Any], let models = json["models"] as? [[String:Any]] {
for model in models {
if let name = model["name"] as? String {
_modelList.append(name)
}
}
}
}catch {
print("error")
}
semaphore.signal()
}
semaphore.wait()
return _modelList
}
And this code is going to get the result:
let api = RestApiManager()
var result:[String] = api.getAllModels()
print(result)
How to relsove this issuse?
Thank you

Use completion
func getAllModels( completion: #escaping ([String] ,Bool) -> Void) {
var modelList:[String] = []
let url = BASE_URL + "getAllProductAndModelv2"
Alamofire.request(url, method:.get, parameters: [:], encoding: JSONEncoding.default).responseJSON { response in
let data = NSData(contentsOf: URL(string: url)!)
do {
if let data = data, let json = try JSONSerialization.jsonObject(with: data as Data) as? [String: Any], let models = json["models"] as? [[String:Any]] {
for model in models {
if let name = model["name"] as? String {
modelList.append(name)
}
}
completion(modelList,true)
}
}catch {
print("error")
completion([],false)
}
}
}
Then call it
self.getAllModels { (data, success) in
if(success)
{
// use data
}
}

Related

Add site with content blocker extension

Hi I am writing a content blocker app.
In this app I want to allow the user add a website that he wants to block.
How can i do that? I used SFContentBlockerManager.reloadContentBlocker(withIdentifier: blockerIdentifier) but it's just activate filter of block list
Thats my protocol on which i write domain(website) how can implement it here to my blocklist in content blocker extension
extension WhiteBlackViewController: AddDomainViewControllerDelegate {
func addDomain(text: String?) {
if listSwitch.isOn {
viewModel.items.append(text ?? "")
viewModel.filtered.append(text ?? "")
tableView.reloadData()
}
}
}
Thats my content blocker:
class ContentBlockerRequestHandler: NSObject, NSExtensionRequestHandling {
func beginRequest(with context: NSExtensionContext) {
let documentFolder = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.cyberGuard")
guard let jsonURL = documentFolder?.appendingPathComponent("whiteList.json") else { return }
let attachment = NSItemProvider(contentsOf: jsonURL)
let item = NSExtensionItem()
item.attachments = [attachment!]
context.completeRequest(returningItems: [item], completionHandler: nil)
}
}
So i already has a solution for this.
You just need create appGroup between your extension and your app
And after that write in another file json and activate it
func activateFilterBlock(fileName: String, website: String, realPath: String) {
viewModel.dictionary.append(["action": ["type": "block"], "trigger": ["url-filter": "\(website)"]])
let jsonData = try! JSONSerialization.data(withJSONObject: viewModel.dictionary, options: .prettyPrinted)
if let json = String(data: jsonData, encoding: String.Encoding.utf8) {
let file = "\(fileName).json"
if let dir = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.cyberGuard") {
let path = dir.appendingPathComponent(file)
do {
try json.write(to: path, atomically: false, encoding: String.Encoding.utf8)
let id = "\(realPath).json"
SFContentBlockerManager.reloadContentBlocker(withIdentifier: id) {error in
guard error == nil else {
print(error ?? "Error")
return
}
print("Reloaded")
}
} catch {
print(error.localizedDescription)
}
}
}
}
If you want receive this json you just can get it from new created json file
func getJSON(fileName: String, success: #escaping(Success), onError: #escaping(OnError)) {
let groupUrl: URL = FileManager().containerURL(forSecurityApplicationGroupIdentifier: "group.cyberGuard")!
if let path = URL(string: "\(fileName).json", relativeTo: groupUrl) {
do {
let data = try Data(contentsOf: path)
let value = try JSONDecoder().decode(WhiteBlackList.self, from: data)
items = value.map({ $0.trigger.urlFilter })
filtered = value.map({ $0.trigger.urlFilter })
if let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [[String: [String: Any]]] {
dictionary = json
}
success()
} catch {
onError(error.localizedDescription)
}
}
}
If it helps, let me know :)

Getting Cell Count after network operation

I am trying to get the collectionViewCell count from the network request but the value turns out to be always 0 (to which I initialised the count variable) I want the view to load the cells after I get it's count from the get request.What is it I'm doing wrong I have written this code after super.viewDidLoad().
DispatchQueue.global(qos:.background).async {
let token = "---------------------------"
let url = URL(string: "https:----------home.json?token="+token)!
let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
guard let data = data else { return }
// print(String(data: data, encoding: .utf8)!)
let jsonWithObjectRoot = try? JSONSerialization.jsonObject(with: data, options: [])
// print(json!)
if let dictionary = jsonWithObjectRoot as? [String: Any] {
if let data = dictionary["data"] as? [String:Any]{
if let posts = data["posts"] as? [Any]{
count = posts.count
//print(count) //the value here is 2
for object in posts{
if let contentString = object as? [String: Any] {
print(contentString["title"] as! String)
// print(contentString["entered"]as! String)
}
}
}
}
}
}
task.resume()
/* end Request */
DispatchQueue.main.async{
self.collectionView.reloadData()
self.collectionView.collectionViewLayout.invalidateLayout()
}
}
Classic async case. You network calls are async, so your reload should happen inside the completion of the network call.
DispatchQueue.global(qos:.background).async {
let token = "---------------------------"
let url = URL(string: "https:----------home.json?token="+token)!
let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
guard let data = data else { return }
// print(String(data: data, encoding: .utf8)!)
let jsonWithObjectRoot = try? JSONSerialization.jsonObject(with: data, options: [])
// print(json!)
if let dictionary = jsonWithObjectRoot as? [String: Any] {
if let data = dictionary["data"] as? [String:Any]{
if let posts = data["posts"] as? [Any]{
count = posts.count
//print(count) //the value here is 2
DispatchQueue.main.async{
self.collectionView.reloadData()
self.collectionView.collectionViewLayout.invalidateLayout()
}
for object in posts {
if let contentString = object as? [String: Any] {
print(contentString["title"] as! String)
// print(contentString["entered"]as! String)
}
}
}
}
}
}
task.resume()
/* end Request */
}
You have to reload after getting data from the network
count = posts.count
//print(count) //the value here is 2
DispatchQueue.main.async{
self.collectionView.reloadData()
}

How to grab data from an API using Swift 4 and Alamofire

I'm trying to get data from an API with no documentation.
My code is
let URL_MAIN = "http://evarsity.srmuniv.ac.in/srmswi/usermanager/youLogin.jsp"
let URL_ATTENDANCE = "http://evarsity.srmuniv.ac.in/srmswi/resource/StudentDetailsResources.jsp?resourceid=7"
let URL_TIMETABLE = "http://evarsity.srmuniv.ac.in/srmswi/resource/StudentDetailsResources.jsp?resourceid=5"
func getData(url: String) {
Alamofire.request(url, method: .get)
.responseData { response in
if response.result.isSuccess {
print("Sucess! Got the data")
guard let data = response.result.value else { return }
print(data)
} else {
print("Error: \(String(describing: response.result.error))")
}
}
I am getting the response as 51406 bytes.
I need to get the actual data in either JSON or some other format. Here is the api link for python
https://github.com/arjunmahishi/srm-erp-api/blob/master/erp.py
Convert your responseData to a dictionary using the function i provided below and then parse the data accordingly.Here, i m getting a JSON response in the form of a dictionary.
let strResponse = "\(responseString.value!)"
let arr = strResponse.components(separatedBy: "\n")
let dict = convertStringToDictionary(str:(arr.last ?? "")!)
self.Message = dict?["message"] as! String
let responseStatus = dict?["status"] as! NSString
public func convertStringToDictionary(str:String) -> [String: Any]? {
if let data = str.data(using: .utf8) {
do {
return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
} catch {
print(error.localizedDescription)
}
}
return nil
}

How to fetch JSON data from a url using URLSession?

I am working on an iOS application in which I have to fetch data from this url .
As I can see this url contain JSON data so here should I need to parse it or not I am not getting it how to get this JSON data.
Here is my code.
import UIKit
import SwiftyJSON
typealias ServiceResponse = (ApiResponseData, NSError?) -> Void
class ApiManager: NSObject {
var session:URLSession? = nil
var urlRequest:URLRequest? = nil
override init(){
super.init()
urlRequest = URLRequest(url: URL(string:"https://dl.dropboxusercontent.com/s/2iodh4vg0eortkl/facts.json")!)
urlRequest?.addValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
session = URLSession(configuration: .default)
}
func callRestApiToFetchDetails(onCompletion: #escaping ServiceResponse) {
let task = session?.dataTask(with: urlRequest!, completionHandler: {data, response, error -> Void in
print("Response = \(data)")
do {
let jsonData = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! NSDictionary
// Do Stuff
print("\(jsonData)")
} catch {
// handle error
print("Error in parsing - \(error)")
}
})
task?.resume()
}
}
But I am getting error in parsing.
You web service response is String.Encoding.ascii that convert into
String.Encoding.utf8 after you have to convert through
NSDictionary JSONSerialization.
Try this method to work.
let url = "https://dl.dropboxusercontent.com/s/2iodh4vg0eortkl/facts.json"
URLSession.shared.dataTask(with: URL(string: url)!) { (data, res, err) in
if let d = data {
if let value = String(data: d, encoding: String.Encoding.ascii) {
if let jsonData = value.data(using: String.Encoding.utf8) {
do {
let json = try JSONSerialization.jsonObject(with: jsonData, options: []) as! [String: Any]
if let arr = json["rows"] as? [[String: Any]] {
debugPrint(arr)
}
} catch {
NSLog("ERROR \(error.localizedDescription)")
}
}
}
}
}.resume()

Can't get data from Dark Sky API

I try to get information about the weather hourly from the Dark Sky API, but the code stops working at the if let data = hourly["data"] as? [String : AnyObject] line (checked with printing stuff after every line). I want to know what is wrong with my code. I think it could be something with the "data" let, but I don't know for sure.
let Task2 = URLSession.shared.dataTask(with: urlRequestDark) { (data, response, error) in
if error == nil {
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String : AnyObject]
if let hourly = json["hourly"] as? [String : AnyObject] {
if let data = hourly["data"] as? [String : AnyObject]{
if let hourNum = data["14"] as? [String : AnyObject] {
if let chanceRain = hourNum["precipProbability"] as? Float{
self.chanceHour1 = String(chanceRain)
}
DispatchQueue.main.sync {
self.ChanceRainLabel.text = self.chanceHour1
}
}
}
}
} catch let jsonError {
print(jsonError.localizedDescription)
}
}
}
Task2.resume() test
The strange part is, this does work:
let urlRequestDark = URLRequest(url: URL (string: "https://api.darksky.net/forecast/(API Key)/(coordinates)")!)
let Task = URLSession.shared.dataTask(with: urlRequestDark) { (data, response, error) in
if error == nil {
do{
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String : AnyObject]
if let currently = json["currently"] as? [String : AnyObject] {
if let chance2 = currently["precipProbability"] as? Float{
print(String(chance2))
self.chance = String(Int(chance2 * 100)) + "%"
self.PreType = currently["precipType"] as? String
}
if let _ = json["error"]{
}
DispatchQueue.main.sync{
self.TypeLabel.text = self.PreType
self.ChanceLabel.text = self.chance
}
}
}catch let jsonError{
print(jsonError.localizedDescription)
}
}
}
Task.resume()
You've made couple mistakes.
First, "data" is an array of dictionaries, so it should be cast to [[String : AnyObject]].
Second, you're trying to subscript array by String, not Int.
Third, using self in escaping closures potentially creates retain cycles.
Let me propose you some fixed and adjusted code.
let task2 = URLSession.shared.dataTask(with: urlRequestDark) { [weak self] (data, response, error) in
guard error == nil else { return }
do {
if let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? [String : AnyObject],
let hourly = json["hourly"] as? [String : AnyObject],
let data = hourly["data"] as? [[String : AnyObject]],
data.count > 14,
let chanceRain = data[14]["precipProbability"] as? Float {
self?.chanceHour1 = String(chanceRain)
DispatchQueue.main.sync {
self?.ChanceRainLabel.text = self?.chanceHour1
}
}
} catch let jsonError {
print(jsonError.localizedDescription)
}
}
task2.resume()
Try like this
import UIKit
class WebService: NSObject {
var session = URLSession()
public class var sharedInstance: WebService {
struct Singleton {
static let instance = WebService()
}
return Singleton.instance
}
override init() {
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = 30.0
configuration.timeoutIntervalForResource = 60.0
session = URLSession(configuration: configuration)
}
public func weatherData(coordinate:String,APIkey:String,completion:#escaping (_ responsedata:NSDictionary?,_ error:NSError?) -> Void) {
var Baseurl = "https://api.darksky.net/forecast/\(APIkey)/\(coordinate)"
Baseurl = Baseurl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
let weatherRequestUrl = URL(string: Baseurl)
let request = NSMutableURLRequest(url: weatherRequestUrl!)
let task = session.dataTask(with: request as URLRequest) { (data, response, error) in
guard error == nil && data != nil else {
return
}
if let httpStatus = response as? HTTPURLResponse{
if httpStatus.statusCode != 200 {
print("Something is wrong")
}
}
do {
let WindlocationData = try JSONSerialization.jsonObject(with: data! as Data, options:.allowFragments) as! NSDictionary
print(WindlocationData)
completion(WindlocationData,nil)
}
catch let error as NSError {
completion(nil,error)
}
}
task.resume()
}
}
And call API like this!
func callAPI(latlong:String,APIkeyParm:String) {
WebService.sharedInstance.weatherData(coordinate: latlong,APIkey: APIkeyParm) { (responsData, error) in
if error == nil{
print("Response data is-\(responsData)")
}
}
}
Call the method like this
let latlongStr = "\(latitude),\(longitude)"
self.callAPI(latlong: latlongStr,APIkeyParm: "APIKeyString")
One importent thing you need to pass latlong like this format 23.022504999999999,72.571362100000002

Resources