Alamofire Response Property List - xcode

I'm going through a tutorial and am attempting to make an alamofire request to a property list. In the closure for the response property list, I use the arguments (_, _, result). However, XCode gives me the error:
Cannot convert value of type '(_, _, _) -> Void' to expected argument
type 'Response -> Void'
I am using alamofire 3.0 beta.

Alamofire right now is in version 3.3 according to the releases in the repository, since the version 3.0 it has change a little.
In you use the Response Handler your closure need to look like this:
Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
.response { request, response, data, error in
print(request)
print(response)
print(data)
print(error)
}
And if you use for example the Response JSON Handler everything is encapsulated now in the response like in this code:
Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
.responseJSON { response in
print(response.request) // original URL request
print(response.response) // URL response
print(response.data) // server data
print(response.result) // result of response serialization
if let JSON = response.result.value {
print("JSON: \(JSON)")
}
}
Or you can use this code for more easily handling:
Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
.responseJSON { response in
switch(response.result) {
case .Success(let value):
if let JSON = value {
print("JSON: \(JSON)")
}
case .Failure(let error):
print(error.description)
}
}
I hope this help you.

this works for me, if doesn't work for you, paste your code to inspect problem please.
var params : Dictionary<String,String> = ["key":"value"]
Alamofire.request(.POST, "someURL" ,parameters: params).responseJSON()
{
response in
let data = JSON(response.result.value!)
if(data != nil)
{
var status = data["status"] as? String
}
}

Related

Implementing RxSwift with TRON

I am trying to start using RxSwift, therefore I tried to create a function that does a request and I tried to implement the rxResult() function that comes with TRON, the HTTP library I use. But the documentation on this is not very detailed. Can anyone point me in the right direction on what I am doing wrong? This is the function I have written:
static func readAllWithRx() {
let token = UserDefaults.standard.value(forKey: Constants.kTokenUserDefaultsKey) as! String
let url = URL(string: "api/url")!
let request: APIRequest<AssessmentResponse, MyAppError> = APIHelper.tron.request(url.absoluteString)
_ = request.rxResult().subscribe(onNext: { AssessmentResponse in
print("RX AssessmentResponse \(AssessmentResponse)")
}, onError: { Error in
}, onCompleted: {
}, onDisposed: {
})
}
Finally I try to call this request within my Controller using:
let read = Assessments.readAllWithRx()
There’re 2 things at the beginning:
let read = Assessments.readAllWithRx() assumes the function returns something synchronously
Implementation of readAllWithRx you posted doesn’t return anything.
I’ve never used TRON, but as far as I can see, its rxResult() returns an Observable<T> where T is a type of the response. In this case, to get asynchronously AssesmentResponse, you need to subscribe to the observable (as you already did by the way).
Here's an example - an updated implementation of your readAllWithRx (won’t compiled probably, writing code in notepad):
static func readAllWithRx() -> Observable<AssessmentResponse> {
let token = UserDefaults.standard.value(forKey: Constants.kTokenUserDefaultsKey) as! String
let url = URL(string: "api/url")!
let request: APIRequest<AssessmentResponse, MyAppError> = APIHelper.tron.request(url.absoluteString)
return request.rxResult()
}
then, if you need to get AssessmentResponse somewhere in the code:
Assessments.readAllWithRx().subscribe(onNext: { result in
// your response here
print(result)
})

Nesting Alamofire callbacks or return value for Global Usage

I am currently trying to nest Alamofire requests to use data that I have already successfully received using GET requests.
For this piece of code I have used Rob's answer in this question
How to return value from Alamofire
However, I can not either nest the Alamofire requests or use them by separate.
This is what I am trying to do
override func viewDidLoad() {
super.viewDidLoad()
var currentFoodType: String = ""
var currentFoodList: String = ""
//debug
//this is how I get back the token from NSUserDefault
if let myToken = userDefaults.valueForKey("token"){
// calling method to get the user info
getUserInfo(myToken as! String)
// calling method to get the product type
func getFoodCategory(completionHandler: (NSDictionary?, NSError?) -> ()) {
getProductTypes(myToken as! String, completionHandler: completionHandler)
}
getFoodCategory() { responseObject, error in
// use responseObject and error here
let foodTypesJSON = JSON(responseObject!)
//to get one single food category
currentFoodType = (foodTypesJSON["types"][0].stringValue)
print(currentFoodType)
/////////////////////////////////////////
func getFoodsByCategory(completionHandler: (NSDictionary?, NSError?) -> ()) {
print("getting " + currentFoodType)
self.getProductsByType(myToken as! String, productType: currentFoodType, completionHandler: completionHandler)
}
getFoodsByCategory() { responseObject, error in
// use responseObject and error here
print("responseObject = \(responseObject); error = \(error)")
return
}
return
}
}
Then the two other functions I am calling from there are very straight forward Alamofire requests with callbacks to the completionHandlers above
//GET THE PRODUCT TYPES FROM THE SERVER
func getProductTypes(myToken: String, completionHandler: (NSDictionary?, NSError?) -> ()) {
let requestToken = "Bearer " + myToken
let headers = ["Authorization": requestToken]
let getProductTypesEndpoint: String = BASE_URL + PRODUCT_TYPES
Alamofire.request(.GET, getProductTypesEndpoint, headers: headers)
.responseJSON{ response in
switch response.result {
case .Success(let value):
completionHandler(value as? NSDictionary, nil)
case .Failure(let error):
completionHandler(nil, error)
}
}//END ALAMOFIRE GET responseJSON
}
The above function returns a single food like "Desserts" which will be used in the following function to GET all the desserts from the server
//GET THE PRODUCTS FROM THE SERVER GIVEN A CATEGORY
func getProductsByType(myToken: String, productType: String, completionHandler: (NSDictionary?, NSError?) -> ()){
let requestToken = "Bearer " + myToken
let headers = ["Authorization": requestToken]
let getProductTypesEndpoint: String = BASE_URL + PRODUCT_BY_TYPE + productType
Alamofire.request(.GET, getProductTypesEndpoint, headers: headers)
.responseJSON { response in
switch response.result {
case .Success(let value):
print("no errors")
let auth = JSON(value)
print("The pbt GET description is: " + auth.description)
completionHandler(value as? NSDictionary, nil)
case .Failure(let error):
print("there was an error")
completionHandler(nil, error)
}
}//END ALAMOFIRE GET responseJSON
}
and this works well because when I print within the getProductsByType function
using
print("The pbt GET description is: " + auth.description)
I get the JSON with all the products but the problem is in the viewDidload function where I am nesting the callbacks
getFoodsByCategory() { responseObject, error in
// use responseObject and error here
print("responseObject = \(responseObject); error = \(error)")
return
}
the print within that bit is showing me that something is wrong so I can not parse my response as I desire.
Because I get the following
responseObject = nil; error = nil
So my guess is that there must a be a different method to nest these callbacks?
Take a look at chained promises from PromiseKit. This also works well with Alamofire:
func loadFoo() -> Promise<Bar> {
return Promise<Bar> { fulfill, reject in
Alamofire.request(.GET, "url")
.responseJSON { response in
switch response.result {
case .Success(let value):
let bar = Bar(fromJSON: value)
fulfill(bar)
case .Failure(let error):
reject(error)
}
}
}
}
// Usage
getBar()
.then { bar -> Void in
// do something with bar
}
.error { error in
// show error
}
This is very simple example, but you can find more relevant examples in documentation.

Can't make Alamofire run in the simulator

i have installed alamo fire and cannot seem to make a request with it.
#IBAction func loginButtonTapped(sender: UIButton) {
let groupLogin = groupUserNameEntry.text;
let groupPassword = groupPasswordEntry.text;
print("line of debug code before request")
Alamofire.request(.GET, "http://api.myserver.com/folks/authenticate", parameters: ["login": groupLogin!, "password": groupPassword!])
.responseJSON { response in
print(response.request) // original URL request
print(response.response) // URL response
print(response.data) // server data
print(response.result) // result of response serialization
print("line of debug code inside request")
if let JSON = response.result.value {
print("JSON: \(JSON)")
}
}
when run in the simulator i get the first line of debug code before request but the output in the "All Output" viewer is (lldb), which i understand to mean low level debugger. It seems like the request is not getting made, but there is no error output. The url works fine in a browser.
The text of a UITextField is an optional value, so what you are doing is assigning to groupLogin an optional value, but groupLogin is not an optional value type, so everything breaks.
You need to safely unwrap optional values, there're many ways to achieve this, but in my opinion guard is the best:
#IBAction func loginButtonTapped(sender: UIButton) {
guard let groupLogin = groupUserNameEntry.text else {
print("groupUserNameEntry.text is nil, stop execution")
return
}
guard let groupPassword = groupPasswordEntry.text else {
print("groupPasswordEntry.text is nil, stop execution")
return
}
print("line of debug code before request")
Alamofire.request(.GET, "http://api.myserver.com/folks/authenticate", parameters: ["login": groupLogin, "password": groupPassword])
.responseJSON { response in
print(response.request) // original URL request
print(response.response) // URL response
print(response.data) // server data
print(response.result) // result of response serialization
print("line of debug code inside request")
if let JSON = response.result.value {
print("JSON: \(JSON)")
}
}

Cannot specialize non-generic type ResponseSerializer

From the documentation and the 2.0 Migrate Guide I tried to use Response Serialization but I'm having the following errors. I can't seem to figure out the problems. I'm also having the same errors with ResponseCollectionSerializable.
You should use GenericResponseSerializer that conforms to ResponseSerializer:
public protocol ResponseObjectSerializable {
init?(response: NSHTTPURLResponse, representation: AnyObject)
}
extension Request {
public func responseObject<T: ResponseObjectSerializable>(completionHandler: (NSURLRequest?, NSHTTPURLResponse?, Result<T>) -> Void) -> Self {
let responseSerializer = GenericResponseSerializer<T> { request, response, data in
let JSONResponseSerializer = Request.JSONResponseSerializer(options: .AllowFragments)
let result = JSONResponseSerializer.serializeResponse(request, response, data)
switch result {
case .Success(let value):
if let
response = response,
responseObject = T(response: response, representation: value)
{
return .Success(responseObject)
} else {
let failureReason = "JSON could not be serialized into response object: \(value)"
let error = Error.errorWithCode(.JSONSerializationFailed, failureReason: failureReason)
return .Failure(data, error)
}
case .Failure(let data, let error):
return .Failure(data, error)
}
}
return response(responseSerializer: responseSerializer, completionHandler: completionHandler)
}
}
ResponseSerializer is the protocol in which all response serializers must conform to.

Swift URL Response is nil

I have created a custom DataManager class. Inside it I want to fetch data in a method and return an NSData object to convert to JSON afterwards.
I have tried to get the data using the completionHandler but no luck:
class func fetchData() -> NSData? {
var session = NSURLSession.sharedSession(),
result = NSData?()
let DataURL : NSURL = NSURL(string: "http://...file.json")!
let sessionTask = session.dataTaskWithURL(DataURL, completionHandler: { (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in
result = data
})
sessionTask.resume()
return result
}
The dataTask runs asynchronously. That means that the completion handler closure will not be called by the time you return from fetchData. Thus, result will not have been set yet.
Because of this, you should not try to retrieve data synchronously from an asynchronous method. Instead, you should employ an asynchronous completion handler pattern yourself:
class func fetchData(completion: #escaping (Data?, Error?) -> Void) {
let session = URLSession.shared
let url = URL(string: "http://...file.json")!
let task = session.dataTask(with: url) { data, response, error in
completion(data, error)
}
task.resume()
}
And you'd call it like so:
MyClass.fetchData { data, error in
guard let data = data, error == nil else {
print(error ?? "Unknown error")
return
}
// use `data` here; remember to dispatch UI and model updates to the main queue
}
// but do not try to use `data` here
...
FYI, for the original pre-Swift 3 syntax, see previous revision of this answer.

Resources