Ambiguous reference to member upload alamofire - ios

I am receiving this error when trying to upload a picture to my web server. I just copied and pasted the alamofire sample from github and I receive an error right away. My code is as follows:
let data = UIImageJPEGRepresentation(picOutlet.image, 0.5)
Alamofire.upload(.POST, "phpurlhere", file: photo)
.progress { bytesWritten, totalBytesWritten, totalBytesExpectedToWrite in
print(totalBytesWritten)
// This closure is NOT called on the main queue for performance
// reasons. To update your ui, dispatch to the main queue.
dispatch_async(dispatch_get_main_queue()) {
print("Total bytes written on main queue: \(totalBytesWritten)")
}
}
.validate()
.responseJSON { response in
debugPrint(response)
}
UPDATE: I added JPEG representation to pass to alamofire function but still getting same error.

The issue is that the upload function:
Alamofire.upload(.POST, "phpurlhere", file: photo)
is expecting an object of type NSURL for the file: parameter. You are giving it a UIImage.
If your goal is to upload picOutlet.image using the upload function, try the following:
let data = UIImageJPEGRepresentation(picOutlet.image, 0.5)
Alamofire.upload(.POST, "phpurlhere", data: data)
.progress { bytesWritten, totalBytesWritten, totalBytesExpectedToWrite in
print(totalBytesWritten)
// This closure is NOT called on the main queue for performance
// reasons. To update your ui, dispatch to the main queue.
dispatch_async(dispatch_get_main_queue()) {
print("Total bytes written on main queue: \(totalBytesWritten)")
}
}
.validate()
.responseJSON { response in
debugPrint(response)
}

try this
Alamofire.upload(photoURL, to: "phpurlhere", method: .post, headers:nil)
.uploadProgress { progress in // main queue by default
progressView.progress = Float(progress.fractionCompleted)
}
.downloadProgress { progress in // main queue by default
print("Download Progress: \(progress.fractionCompleted)")
}
.responseJSON { response in
debugPrint(response)
}

Related

Tracking progress in Alamofire Request [duplicate]

This question already has answers here:
Progress of a Alamofire request
(3 answers)
Closed 3 years ago.
I wanna know it is possible to show progress for request. I convert my images to base64 string and send it to my server with parameter. Is there a way to track it's progress? I wanna try something like that.But I cannot add progress section in my Alamofire.request. Is there something that I am missing?
Alamofire.request(.POST, URL, parameters: parameter, encoding: .JSON)
.progress { bytesRead, totalBytesRead, totalBytesExpectedToRead in
// track progress here
}
.responseJSON { response in
// Do your stuff
}
Not sure but I think the current version of Alamofire uses downloadProgress instead of progress:
Alamofire.request(/* ... */).downloadProgress { progress in
progress.fractionCompleted // value between 0 and 1
}
.responseJSON { /* ... */ }
You can do like this
Alamofire.upload(multipartFormData: { (multipartFormData) in
}, with: URL, encodingCompletion: { (result) in
switch result {
case .success(let upload, _, _):
upload.uploadProgress(closure: { (Progress) in
// Here you get the progress
print(Progress.fractionCompleted)
})
upload.responseJSON { response in
case .failure( _ ):
}
})

How to show an alert to the user inside a completion block in swift 5

I have an app that makes an API call to a web server. I finally got the API call to work correctly and can now parse the JSON data the server returns, but I am stuck with trying to show an alert to the user if the request fails. For example, my server can return {"success": false, "error": "You didn't ask nicely"} Obviously that error is not real, but a representation of what can be returned. I can only check the error inside the completion block of the URLSession.shared.dataTask, but if I try to show an alert from inside that I get the error that I cannot perform any operation from a background thread on the UI.
The code is rather simple right now...
URLSession.shared.dataTask(with: self.request) { (data, response, error) in
if let error = error {
completion(.failure(error))
return
}
//continue on with processing the response...
completion(.success(fullResponse))
}.resume()
Then in my calling code I have...
connector.connect(pin) { (result) in
switch(result) {
case .success(let response):
if let response = response {
if response.success {
//do things
} else {
self.alert(title: "Error while connecting", message: response.error)
}
}
case .failure(let error):
self.alert(title: "Unable to connect", message: error)
}
}
That is causing the error that I can't do anything on the ui thread from a background thread. If that is the case, how do I let the user know that the API call failed? I have to be able to notify the user. Thank you.
You need to wrap it inside DispatchQueue.main.async as callback of URLSession.shared.dataTask occurs in a background thread
DispatchQueue.main.async {
self.alert(title: "Error while connecting", message: response.error)
}
Same also for
self.alert(title: "Unable to connect", message: error)
but it's better to wrap all code inside alert function inside the main queue to be a single place
Here's a different approach you can use, instead of calling DispatchQueue.main.async on connector.connect(pin)'s callback you could also do it before you call the completion block on your dataTask like this.
URLSession.shared.dataTask(with: self.request) { (data, response, error) in
if let error = error {
DispatchQueue.main.async {
completion(.failure(error))
}
return
}
//continue on with processing the response...
DispatchQueue.main.async {
completion(.success(fullResponse))
}
}.resume()
By doing this your code inside connector.connect(pin) won't be placed in a pyramid of doom, and everything in the completion block is running on the main thread.
connector.connect(pin) { result in
// everything in here is on the main thread now
}

How to not freeze the UI, and wait for response?

I've been trying since the morning but I didnt achieve what I wanted.
I tried DispatchQueue.main.async and completion block but my "Submit" button in the UI still freezes waiting for the data to be returned from the server. This is my code:
func createData(request:Crudpb_CreateRequest, with completion: #escaping (String) -> Void) throws {
DispatchQueue.main.async {
self.response = try! self.client.create(request) // <---- How to handle error for this server call when the server is not available or is down?
completion(self.response.result)
}
}
I just noticed Im calling the 1st method from the following which is a Synchronous Unary which might be the reason behind the problem. But again I dont know how to call the second function in the fallowing:
/// Synchronous. Unary.
internal func create(_ request: Crudpb_CreateRequest, metadata customMetadata: Metadata) throws -> Crudpb_CreateResponse {
return try Crudpb_CrudServiceCreateCallBase(channel)
.run(request: request, metadata: customMetadata)
}
/// Asynchronous. Unary.
#discardableResult
internal func create(_ request: Crudpb_CreateRequest, metadata customMetadata: Metadata, completion: #escaping (Crudpb_CreateResponse?, CallResult) -> Void) throws -> Crudpb_CrudServiceCreateCall {
return try Crudpb_CrudServiceCreateCallBase(channel)
.start(request: request, metadata: customMetadata, completion: completion)
}
Server Side Code:
func (*server) Create(ctx context.Context, req *crudpb.CreateRequest) (*crudpb.CreateResponse, error) {
var result string
firstName := req.GetAccount().GetFirstName()
lastName := req.GetAccount().GetLastName()
// id := gocql.TimeUUID()
fmt.Println("Triggered CREATE function on Go Server " + firstName + " " + lastName + "! Yayy!")
result = fmt.Sprintf("id for %s %s : %s", firstName, lastName, strconv.Itoa(rand.Intn(100)))
return &crudpb.CreateResponse{
Result: result,
}, nil
I need this app / submit button not to freeze while it fetches result from server.
Please help.
You are still performing work on the main thread.. async only makes the createData() method to return before the task is completed.. but the task will still be processed at some time in the main thread and during this time your application will become unresponsive.. try using a global queue instead.. to keep your main thread clean..
Dont forget to perform all your UI work on the main thread after getting your response.
Use the asynchronous function instead and call the completion block inside create function's completion.
func createData(request:Crudpb_CreateRequest, with completion: #escaping (String) -> Void) throws {
try! self.client.create(request) { (response: Crudpb_CreateResponse?, result: CallResult) in
DispatchQueue.main.async {
// This is assuming your completion involves UI operations. Otherwise there is no need for this async call.
let stringOutput = String(data: result.resultData!, encoding: String.Encoding.utf8))
completion(stringOutput)
}
}
}
Remove DispatchQueue.main.async block from the createData method
func createData(request:Crudpb_CreateRequest, with completion: #escaping (String) -> Void) throws {
self.response = try! self.client.create(request)
completion(self.response.result)
}
Use main queue only where you update the UI from the api response
myobj.createData(request: request, with: { string in
print(string)//background thread
DispatchQueue.main.async {
self.label.text = sting//main thread
}
})
The UI freeze because you are doing too much work on the main thread. You should find out what function blocks the main thread.
The instruments time profiler is an easy way to see which function is spending too much time.

Alamofire 4.0 ambiguous reference on upload

I am trying to upload using alamofire, I am using the following code:
Alamofire.upload(urlRequest.0, to: urlRequest.1, method: .put)
.uploadProgress(queue: DispatchQueue.utility) { progress in
print("Upload Progress: \(progress.fractionCompleted)")
}
.responseJSON { response in
//Some code here
}
Where urlRequest is a tuple: (URLConvertible, Data). I am getting the compiler error : "Ambiguous reference to member 'upload(_:to:method:headers:)'". Any ideas what I am doing wrong here? Any pointers would be really appreciated! Thanks!
You may need to add the headers parameter:
Alamofire.upload(urlRequest.0, to: urlRequest.1, method: .put, headers: nil)
.uploadProgress { progress in
print("Upload Progress: \(progress.fractionCompleted)")
}
while a tuple's types should stand in this order: (Data, URLConvertible)

Deadlock inside NSURLSession delegate queue

I'm experiencing a deadlock inside one of the operations in the NSUrlSession delegate queue when using Alamofire.
it happens when i'm doing at least one download and one upload simultaneously (all requests are done through the default Alamofire manager). Is there any problem doing so from multiple threads? (either in NSUrlSession or Alamofire)
it seems to be stuck on __psynch_mutexwait in one of the operations in the NSURLSession delegate queue, and it completely shuts down the app's ability to make network requests through Alamofire (because the delegate won't be called ever).
as I said the download and upload called simultaneously on 2 different queues (one of them is usually called on the main thread)
upload example :
Alamofire.upload(.POST, uploadURL,
multipartFormData: { multipartFormData in
multipartFormData.appendBodyPart(data: x.dataUsingEncoding(NSUTF8StringEncoding)!, name: "X")
multipartFormData.appendBodyPart(data: fileData, name: "file", fileName: "Y", mimeType: "application/octet-stream")
}
},
encodingCompletion: { encodingResult in
switch encodingResult {
case .Success(let upload, _, _):
upload.response { (request, response, data, error) -> Void in
if let error = error {
callback("Failure", "\(error)")
} else {
callback("SUCCESS", nil)
}
}
case .Failure(let encodingError):
callback(nil, "Failed due to \(encodingError)")
}
}
)
download example :
Alamofire.download(.GET, downloadUrl, parameters: ["a": "a", "b": "b"], destination:
{
tempURL, response in
return path
}).response {
(request, response, _, error) in
let data = NSData(contentsOfURL: path)
doSomeStuffWithDownloadedData(data)
// make another request after download completed
Alamofire.request(.GET, requestUrl, parameters: ["c":"c", "d":"d"]).response {
request, response, data, error in
if let e = error {
log.error("request failed, \(e)")
}
}
}
stack trace
After commenting most of my code I isolated the code causing the problem and it does not related at all to alamofire or NSURLSession.
I have in my own code a call to objc_sync_enter on an array (of objects), it always has a matching objc_sync_exit call on the same array. after changing this call to be on self instead of this array, the deadlock inside NSBlockOperation is gone. It may be related to the fact that an array is not an object but a struct. So if you experience very strange deadlock in your code, I suggest that before you try anything else, make sure you don't have calls of objc_sync_enter on structs.

Resources