Error handling in swift 3 using objectMapper and alamofire - swift3

How i can handle error in completion block if get error from server side.Here is object mapper class for login.
class Login: Mappable {
var result: LoginData?
var success: Bool?
var error: String?
required init?(map: Map){
}
func mapping(map: Map) {
result <- map["data"]
success <- map["success"]
error <- map["error"]
}
}
class LoginData: Mappable {
var name: String?
var title: String?
var token: String?
var imageUrl: String?
required init?(map: Map){
}
func mapping(map: Map) {
name <- map["name"]
title <- map["title"]
token <- map["token"]
name <- map["name"]
imageUrl <- map["imageUrl"]
}
}
Here is my api calling from view controller.
func loginMethod(){
let postData = ["username":loginDict.object(forKey: KUserUserId) as! String,
"password": loginDict.object(forKey: KUserPass) as! String]
userLoginHttp(parameters: postData){ completion in
self.getUserLoginResponse(result: completion)
}
}
func getUserLoginResponse(result: LoginData) {
// Here i do further
}
This is Network class mthod from where i fire the service
//User login web service
func userLoginHttp(parameters:Parameters, completion:#escaping (_
result:LoginData)->()) {
let defaultObject = UserDefaults.standard
var headerToken = String()
if let x = defaultObject.object(forKey: KDeviceToken)
{
headerToken = x as! String
}
else{
headerToken = ""
}
let headers = ["fcmToken": headerToken]
Alamofire.request(KLoginUrl, method: .post, parameters: parameters,encoding: JSONEncoding.default, headers: headers)
.validate()
.responseObject{ (response: DataResponse<Login>) in
switch response.result{
case .success:
let value = response.result.value
completion((value?.result)!)
case .failure(let error):
print(error.localizedDescription)
}
}
}
So how i can handle error in my view controller completion block?

you can just create another handler for errors and call it in error case
func userLoginHttp(parameters:Parameters,
completion:#escaping (_ result:LoginData)->(),
errorHandler:#escaping (_ result:Error,_ statusCode:Int?)->()//error handler
) {
let defaultObject = UserDefaults.standard
var headerToken = String()
if let x = defaultObject.object(forKey: KDeviceToken)
{
headerToken = x as! String
}
else{
headerToken = ""
}
let headers = ["fcmToken": headerToken]
Alamofire.request(KLoginUrl, method: .post, parameters: parameters,encoding: JSONEncoding.default, headers: headers)
.validate()
.responseObject{ (response: DataResponse<Login>) in
switch response.result{
case .success:
let value = response.result.value
completion((value?.result)!)
case .failure(let error):
errorHandler(error,response.response?.statusCode)//call error handler
print(response.response?.statusCode)
print(error.localizedDescription)
}
}
}
usage
func loginMethod(){
let postData = ["username":loginDict.object(forKey: KUserUserId) as! String,
"password": loginDict.object(forKey: KUserPass) as! String]
userLoginHttp(
parameters: postData,
completion:{ completion in
self.getUserLoginResponse(result: completion)
},
errorHandler:{ error,code in
//do your error stuff
})
}
func getUserLoginResponse(result: LoginData) {
// Here i do further
}

Related

Call async func in another function and update UI

Here is my async function class:
class MoviesViewModel: ObservableObject {
#Published var topRated: [Movie] = []
#Published var popular: [Movie] = []
#Published var upcoming: [Movie] = []
func getUpcomingMovies() {
if let movies = getMovies(path: "upcoming") {
DispatchQueue.main.async {
self.upcoming = movies
}
}
}
func getPopularMovies() {
if let movies = getMovies(path: "popular") {
DispatchQueue.main.async {
self.popular = movies
}
}
}
func getTopRatedMovies() {
DispatchQueue.main.async {
if let movies = self.getMovies(path: "top_rated") {
self.topRated = movies
}
}
}
func getMovies(path: String) -> [Movie]? {
var movies: [Movie]?
let urlString = "https://api.themoviedb.org/3/movie/\(path)?api_key=\(apiKey)&language=en-US&page=1"
guard let url = URL(string: urlString) else { return [] }
let session = URLSession.shared
let dataTask = session.dataTask(with: url, completionHandler: { data, _, error in
if error != nil {
print(error)
}
do {
if let safeData = data {
let decodedData = try JSONDecoder().decode(NowPlaying.self, from: safeData)
DispatchQueue.main.async {
movies = decodedData.results
}
}
}
catch {
print(error)
}
})
dataTask.resume()
return movies
}
}
When I printed the movies in getMovies function, I can get movies from api without problem. However, UI does not update itself. I used DispatchQueue.main.async function but it did not solve my problem. What can I do in this situation?
dataTask works asynchronously. Your code returns nil even before the asynchronous task is going to start. You have to use a completion handler as described in Returning data from async call in Swift function.
I highly recommend to use async/await in this case. You get rid of a lot of boilerplate code and you don't need to care about dispatching threads.
#MainActor
class MoviesViewModel: ObservableObject {
#Published var topRated: [Movie] = []
#Published var popular: [Movie] = []
#Published var upcoming: [Movie] = []
func getUpcomingMovies() async throws {
self.upcoming = try await getMovies(path: "upcoming")
}
func getPopularMovies() async throws {
self.popular = try await getMovies(path: "popular")
}
func getTopRatedMovies() async throws {
self.topRated = try await getMovies(path: "top_rated")
}
func getMovies(path: String) async throws -> [Movie] {
let urlString = "https://api.themoviedb.org/3/movie/\(path)?api_key=\(apiKey)&language=en-US&page=1"
guard let url = URL(string: urlString) else { throw URLError(.badURL) }
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode(NowPlaying.self, from: data).results
}
}

custom error type handling after receiving data from internet

I have RestManager class which is used to fetch data from Internet
class RestManager {
func fetchData<T: Decodable>(url: URL) -> AnyPublisher<T, ErrorType> {
URLSession.shared
.dataTaskPublisher(for: url)
.map { $0.data }
.decode(type: T.self, decoder: JSONDecoder())
.mapError({ error in
if let error = error as? URLError {
switch error.code {
case .notConnectedToInternet, .timedOut, .networkConnectionLost:
return .noInternetConnection
case .cannotDecodeRawData, .cannotDecodeContentData:
return .empty
default:
return .general
}
}
return .general
})
.eraseToAnyPublisher()
}
}
In Repository class there is function getCountriesList which, using RestManager is returning AnyPublisher<[Country], ErrorType> where ErrorType represents enum with custom cases for error handling (.noInternetConnection, .general, .empty)
class Covid19RepositoryImpl: Covid19Repository {
func getCountriesList() -> AnyPublisher<[Country], ErrorType> {
let url = RestEndpoints.countriesList.endpoint()
return RestManager().fetchData(url: url)
}
}
In viewModel class, in function getAllCountries, pipeline is created for fetching and saving data in countries variable, and in .sink in completion I tried to save ErrorType (if there is any error) in specific variable called error
I tried to use like this
class CountriesViewModelImpl: CountriesViewModel {
var repository: Covid19Repository
#Published var countries: [Country] = []
#Published var error: ErrorType?
#Published var loader: Bool = true
private var cancellables: Set<AnyCancellable> = .init()
init(repository: Covid19Repository){
self.repository = repository
getAllCountries()
}
func getAllCountries() {
repository
.getCountriesList()
.receive(on: RunLoop.main)
.sink { error in
self.error = error
}
} receiveValue: { [unowned self] newCountries in
self.countries = newCountries
self.error = nil
self.loader = false
}
.store(in: &cancellables)
}
}
But it returns Cannot assign value of type 'Subscribers.Completion' to type 'ErrorType'
Is there any other way I can handle error?
sink returns an enum in the receiveCompletion closure with finished and failure cases
.sink { completion in
switch completion {
case .finished: print("finished")
case .failure(let error): self.error = error
}
} receiveValue: ...

swift | unresolved identifier error

Here is the code:
let task: URLSessionDataTask = session.dataTask(with: request as URLRequest) { (data, response, error) -> Void in
// Get the HTTP status code of the request.
let statusCode = (response as! HTTPURLResponse).statusCode
if statusCode == 200 {
// Convert the received JSON data into a dictionary.
do {
if let dataDictionary = (try? JSONSerialization.jsonObject(with: data!, options: [JSONSerialization.ReadingOptions.mutableContainers])) as? [String:Any] { let accessToken = dataDictionary["access_token"] as? String }
UserDefaults.setObject(accessToken, forKey: "LIAccessToken")
UserDefaults.standard.synchronize()
DispatchQueue.main.async(execute: { () -> Void in
self.dismiss(animated: true, completion: nil)
})
}
catch {
print("Could not convert JSON data into a dictionary.")
}
}
new Code: ( this is from app coda that is not able to compile in latest swift,https://github.com/appcoda/LinkedInSignInDemo/blob/master/LISignIn/WebViewController.swift)
let dataDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)
let accessToken = dataDictionary["access_token"] as! String
NSUserDefaults.standardUserDefaults().setObject(accessToken, forKey: "LIAccessToken")
NSUserDefaults.standardUserDefaults().synchronize()
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.dismissViewControllerAnimated(true, completion: nil)
})
You have to use like this :
You defined accessToken in if loop. And you are accessing it outside of it.
if let dataDictionary = (try? JSONSerialization.jsonObject(with: data!, options: [JSONSerialization.ReadingOptions.mutableContainers])) as? [String:Any] {
let accessToken = dataDictionary["access_token"] as? String
UserDefaults.setObject(accessToken, forKey: "LIAccessToken")
}

api youtube in swift 3 error 403

I am trying to use youtube api in ios swift, and following this tutorial
http://www.appcoda.com/youtube-api-ios-tutorial/
HTTP Status Code = 403
Error while loading channel details: nil
I'm using swift 3
var urlString = "https://www.googleapis.com/youtube/v3/search?part=snippet&q=\(textField.text)&type=\(type)&key=\(apiKey)"
urlString = urlString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!
// Create a NSURL object based on the above string.
let targetURL = URL(string: urlString)
// Get the results.
performGetRequest(targetURL, completion: { (data, HTTPStatusCode, error) -> Void in
if HTTPStatusCode == 200 && error == nil {
// Convert the JSON data to a dictionary object.
do {
let resultsDict = try JSONSerialization.jsonObject(with: data!, options: []) as! Dictionary<String, AnyObject>
// Get all search result items ("items" array).
let items: Array<Dictionary<String, AnyObject>> = resultsDict["items"] as! Array<Dictionary<String, AnyObject>>
// Loop through all search results and keep just the necessary data.
for i in 0 ..< items.count {
let snippetDict = items[i]["snippet"] as! Dictionary<String, AnyObject>
// Gather the proper data depending on whether we're searching for channels or for videos.
if self.segDisplayedContent.selectedSegmentIndex == 0 {
// Keep the channel ID.
self.desiredChannelsArray.append(snippetDict["channelId"] as! String)
}
else {
// Create a new dictionary to store the video details.
var videoDetailsDict = Dictionary<String, AnyObject>()
videoDetailsDict["title"] = snippetDict["title"]
videoDetailsDict["thumbnail"] = ((snippetDict["thumbnails"] as! Dictionary<String, AnyObject>)["default"] as! Dictionary<String, AnyObject>)["url"]
videoDetailsDict["videoID"] = (items[i]["id"] as! Dictionary<String, AnyObject>)["videoId"]
// Append the desiredPlaylistItemDataDict dictionary to the videos array.
self.videosArray.append(videoDetailsDict)
// Reload the tableview.
self.tblVideos.reloadData()
}
}
} catch {
print(error)
}
// Call the getChannelDetails(…) function to fetch the channels.
if self.segDisplayedContent.selectedSegmentIndex == 0 {
self.getChannelDetails(true)
}
}
else {
print("HTTP Status Code = \(HTTPStatusCode)")
print("Error while loading channel videos: \(error)")
}
// Hide the activity indicator.
self.viewWait.isHidden = true
})
return true
}
// MARK: Custom method implementation
func performGetRequest(_ targetURL: URL!, completion: #escaping (_ data: Data?, _ HTTPStatusCode: Int, _ error: NSError?) -> Void) {
// let request = NSMutableURLRequest(url: targetURL)
// request.httpMethod = "GET"
var request = URLRequest(url: targetURL)
request.httpMethod = "GET"
let sessionConfiguration = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfiguration)
/* let task = session.dataTask(with: request, completionHandler: { (data: Data?, response: URLResponse?, error: NSError?) -> Void in
DispatchQueue.main.async(execute: { () -> Void in
completion(data, (response as! HTTPURLResponse).statusCode, error)
})
} as! (Data?, URLResponse?, Error?) -> Void)*/
/* let task = session.dataTask(with: request, completionHandler: ({ (data: Data?, response: URLResponse?, error: NSError?) -> Void in
DispatchQueue.main.async(execute: { () -> Void in
completion(data as Data?, (response as! HTTPURLResponse).statusCode, error)
})
} as! (Data?, URLResponse?, Error?) -> Void))*/
let task = session.dataTask(with: request) { data, response, error in DispatchQueue.main.async { completion(data, (response as! HTTPURLResponse).statusCode, error as? NSError) } }
task.resume()
}
First of all the JSON dictionary representation in Swift 3 is [String:Any] (aka Dictionary<String,Any>)
Second of all in Swift 3 all parameter labels in closures have been removed
func performGetRequest(_ targetURL: URL, completion: #escaping (Data?, Int, NSError?) -> Void) {
Do not use implicit unwrapped optionals for method parameter types. Either use regular optional (?) or non-optional.
Error 403 means Forbidden Access. Make sure you have the correct apiKey from google/youtube developer.
I also used the appcoda youtube api tutorial (which is in Swift 2 I think) and this is a working version of mine for swift 3.
func getVideosForChannelAtIndex() {
let urlString = "https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&playlistId=\(playlistID)&maxResults=\(maxResults)&key=\(apiKey)"
// Create a NSURL object based on the above string.
let targetURL = URL(string: urlString)
// Fetch the playlist from Google.
performGetRequest(targetURL!) { (data, HTTPStatusCode, error) -> Void in
if HTTPStatusCode == 200 && error == nil {
do {
self.videos = []
// Convert the JSON data into a dictionary.
let resultsDict = try JSONSerialization.jsonObject(with: data!, options: []) as! Dictionary<AnyHashable, Any>
// Get all playlist items ("items" array).
let items:Array<Dictionary<AnyHashable, Any>> = resultsDict["items"] as! Array<Dictionary<AnyHashable, Any>>
// Use a loop to go through all video items.
// for var i=0; i<items.count; ++i
for i in 0 ..< items.count {
let playlistSnippetDict = (items[i] as Dictionary<AnyHashable, Any>)["snippet"] as! Dictionary<AnyHashable, Any>
let video = Video()
video.title = playlistSnippetDict["title"] as? String
// video.thumbnail =
video.videoId = (playlistSnippetDict["resourceId"] as? Dictionary<AnyHashable, Any>)?["videoId"] as? String
guard let thumbnail = ((playlistSnippetDict["thumbnails"] as? Dictionary<AnyHashable, Any>)?["high"] as? Dictionary<AnyHashable, Any>)?["url"] as? String else {
video.thumbnail = UIImage(named: "Icon1024x1024")
return
}
guard let url:URL? = URL(string: thumbnail), let data:Data? = try? Data(contentsOf: url!) else {
video.thumbnail = UIImage(named: "Icon1024x1024")
return
}
if let dataImage = data {
video.thumbnail = UIImage(data: dataImage)
} else {
video.thumbnail = UIImage(named: "Icon1024x1024")
}
self.videos.append(video)
// Reload the tableview.
self.tblVideos.reloadData()
}
} catch {
print("json error: \(error)")
}
} else {
print("")
print("HTTP Status Code = \(HTTPStatusCode)")
print("")
//Show alertDialog here with Error
print("Error while loading videos: \(error?.localizedDescription)")
let alert = UIAlertView(title: "Oops!", message: error?.localizedDescription, delegate: self, cancelButtonTitle: "OK")
alert.show()
}
// Hide the activity indicator.
self.viewWait.isHidden = true
}
}
This is for the performGetRequest
func performGetRequest(_ targetURL: URL, completion: #escaping (_ data: Data?, _ HTTPStatusCode: Int?, _ error: Error?) -> Void) {
var request = URLRequest(url: targetURL)
request.httpMethod = "GET"
let sessionConfiguration = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfiguration)
let task = session.dataTask(with: request) { data, response, error in
DispatchQueue.main.async(execute: {
completion(data, (response as? HTTPURLResponse)?.statusCode, error)
})
}
task.resume()
}

upload image to server using Alamofire

this is my code that I want to upload image to server using Alamofire, it not error but it can't push image to server. what should I do?
let url = URL(string: urlString)!
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
let parameters = ["name": rname]
do {
urlRequest.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: [])
} catch {
print(error)
}
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
let image = UIImage.init(named: "myImage")
let imgData = UIImageJPEGRepresentation(image!, 0.2)!
Alamofire.upload(multipartFormData: { MultipartFormData in
MultipartFormData.append(imgData, withName: "fileset", fileName: "name", mimeType: "image/jpg")
},with: urlRequest,encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.responseJSON { response in
if let info = response.result.value as? Dictionary<String, AnyObject> {
if let links = info["links"] as? Dictionary<String, AnyObject> {
if let imgLink = links["image_link"] as? String {
print("LINK: \(imgLink)")
}
}
}
} case .failure(let error):
print(error)
}
})
Try below code
let image = UIImage.init(named: "myImage")
let imgData = UIImageJPEGRepresentation(image!, 0.2)!
let parameters = ["name": rname] //Optional for extra parameter
Alamofire.upload(multipartFormData: { multipartFormData in
multipartFormData.append(imgData, withName: "fileset",fileName: "file.jpg", mimeType: "image/jpg")
for (key, value) in parameters {
multipartFormData.append(value.data(using: String.Encoding.utf8)!, withName: key)
} //Optional for extra parameters
},
to:"mysite/upload.php")
{ (result) in
switch result {
case .success(let upload, _, _):
upload.uploadProgress(closure: { (progress) in
print("Upload Progress: \(progress.fractionCompleted)")
})
upload.responseJSON { response in
print(response.result.value)
}
case .failure(let encodingError):
print(encodingError)
}
}
let params: Parameters = ["name": "abcd" "gender": "Male"]
Alamofire.upload(multipartFormData:
{
(multipartFormData) in
multipartFormData.append(UIImageJPEGRepresentation(self.yourimageView.image!, 0.1)!, withName: "image", fileName: "file.jpeg", mimeType: "image/jpeg")
for (key, value) in params
{
multipartFormData.append((value as AnyObject).data(using: String.Encoding.utf8.rawValue)!, withName: key)
}
}, to:yourUrl,headers:nil)
{ (result) in
switch result {
case .success(let upload,_,_ ):
upload.uploadProgress(closure: { (progress) in
//Print progress
})
upload.responseJSON
{ response in
//print response.result
if response.result.value != nil
{
let dict :NSDictionary = response.result.value! as! NSDictionary
let status = dict.value(forKey: "status")as! String
if status=="1"
{
print("DATA UPLOAD SUCCESSFULLY")
}
}
}
case .failure(let encodingError):
break
}
}
Updated code to Swift 5.
In swift 5 there is a change in this line
let imageData = UIImageJPEGRepresentation(image!, 0.2)!
To like this
let imageData = image.jpegData(compressionQuality: 0.50)
Whole code to upload image
let param: [String:Any] = ["your_parameters"]
var image = UIImage()
image = UIImage(named: "edit.png")!
let imageData = image.jpegData(compressionQuality: 0.50)
print(image, imageData!)
AF.upload(multipartFormData: { (multipartFormData) in
multipartFormData.append(imageData!, withName: "file", fileName: "swift_file.png", mimeType: "image/png")
for (key, value) in param {
multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: key)
}
}, to: "your_url")
{ (result) in
switch result {
case .success(let upload, _, _):
upload.uploadProgress(closure: { (progress) in
//Print progress
print("uploading \(progress)")
})
upload.responseJSON { response in
//print response.result
}
case .failure( _): break
//print encodingError.description
}
}
}
The only one working for me at this date:
let headers: HTTPHeaders = [
/* "Authorization": "your_access_token", in case you need authorization header */
"Content-type": "multipart/form-data"
]
AF.upload(
multipartFormData: { multipartFormData in
multipartFormData.append(imageOrVideo!.jpegData(compressionQuality: 0.5)!, withName: "upload_data" , fileName: "file.jpeg", mimeType: "image/jpeg")
},
to: "http://35.227.31.145/new.php", method: .post , headers: headers)
.response { resp in
print(resp)
}
Need to specify name, fileName, mimeType, these are important to many servers
func upload(image: UIImage, completion: (URL?) -> Void) {
guard let data = UIImageJPEGRepresentation(image, 0.9) else {
return
}
Alamofire.upload(multipartFormData: { (form) in
form.append(data, withName: "file", fileName: "file.jpg", mimeType: "image/jpg")
}, to: "https://yourawesomebackend.com", encodingCompletion: { result in
switch result {
case .success(let upload, _, _):
upload.responseString { response in
print(response.value)
}
case .failure(let encodingError):
print(encodingError)
}
})
}
Ok Bro I use this code with Swift 4 and Alamofire
import Foundation
import Alamofire
class UploadImageController: NSObject {
// MARK: - shared
static let shared = UploadImageController()
// MARK: - init
let decoder = JSONDecoder()
// MARK: - uploadImageOnly
func uploadImageWith(endUrl: String, photo: UIImage?, parameters: [String : Any]?, headers: HTTPHeaders?, completion: #escaping (_ success: Bool, _ uploadImageResponse: UploadImageResponse?) -> Void ) {
Alamofire.upload(multipartFormData: { (multipartFormData) in
if let data = UIImageJPEGRepresentation(photo!, 0.5) {
multipartFormData.append(data, withName: "invoice", fileName: "invoice.jpeg", mimeType: "invoice/jpeg")
}
}, usingThreshold: SessionManager.multipartFormDataEncodingMemoryThreshold, to: endUrl, method: .post, headers: headers) { (result) in
switch result {
case .failure(let error):
print("UploadImageController.requestWith.Alamofire.usingThreshold:", error)
completion(false, nil)
case .success(request: let upload, streamingFromDisk: _, streamFileURL: _):
upload.uploadProgress(closure: { (progress) in
print("Upload Progress: \(progress.fractionCompleted)")
})
upload.responseJSON(completionHandler: { (response) in
switch response.result {
case .failure(let error):
print("UploadImageController.requestWith.Alamofire.upload.responseJSON:", error)
completion(false, nil)
case .success( _):
print("UploadImageController.requestWith.Alamofire.upload.responseJSON Succes")
guard let data = response.data else { return }
do {
let uploadImageResponse = try self.decoder.decode(UploadImageResponse.self, from: data)
completion(true, uploadImageResponse)
} catch let jsonError {
print("Error serializing json.ProfileController.getProfile:", jsonError)
completion(false, nil)
}
}
})
}
}
}
// MARK: - uploadImageWithParameters
func uploadImageWithParametersAnd(endUrl: String, photo: UIImage?, parameters: [String : Any]?, headers: HTTPHeaders?, completion: #escaping (_ success: Bool, _ addInvoiceResponse: AddInvoiceResponse?) -> Void ) {
Alamofire.upload(multipartFormData: { (multipartFormData) in
if let data = UIImageJPEGRepresentation(photo!, 0.5) {
multipartFormData.append(data, withName: "invoicePicture", fileName: "invoicePicture.jpeg", mimeType: "invoice/jpeg")
}
for (key, value) in parameters! {
multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: "\(key)")
}
}, usingThreshold: SessionManager.multipartFormDataEncodingMemoryThreshold, to: endUrl, method: .post, headers: headers) { (result) in
switch result {
case .failure(let error):
print("UploadImageController.requestWith.Alamofire.usingThreshold:", error)
completion(false, nil)
case .success(request: let upload, streamingFromDisk: _, streamFileURL: _):
upload.uploadProgress(closure: { (progress) in
print("Upload Progress: \(progress.fractionCompleted)")
})
upload.responseJSON(completionHandler: { (response) in
switch response.result {
case .failure(let error):
print("UploadImageController.requestWith.Alamofire.upload.responseJSON:", error)
completion(false, nil)
case .success( _):
print("UploadImageController.requestWith.Alamofire.upload.responseJSON Succes")
guard let data = response.data else { return }
do {
let addInvoiceResponse = try self.decoder.decode(AddInvoiceResponse.self, from: data)
completion(true, addInvoiceResponse)
} catch let jsonError {
print("Error serializing json.ProfileController.getProfile:", jsonError)
completion(false, nil)
}
}
})
}
}
}
}
For example this AddInvoiceResponse
import Foundation
struct AddInvoiceResponse: Decodable {
let id, message: String?
}
and here UploadImageResponse
import Foundation
struct UploadImageResponse: Codable {
let id, message: String?
}
Try below code For MultipleImage Upload. asked by #Saurabh. However it is better to make upload 1 by 1 instead of uploading all at once.
because if it failed, it will only failed on 1 image. but upload all at once.if 1 file failed user need to restart the uploading process from the beginning.
nevertheless here is what you going have to do if you want to upload multiple data at once.
let image1 = UIImage.init(named: "myImage1")
let image2 = UIImage.init(named: "myImage2")
let image3 = UIImage.init(named: "myImage3")
let image4 = UIImage.init(named: "myImage4")
let imgData1 = UIImageJPEGRepresentation(image!, 0.2)!
let imgData2 = UIImageJPEGRepresentation(image!, 0.2)!
let imgData3 = UIImageJPEGRepresentation(image!, 0.2)!
let imgData4 = UIImageJPEGRepresentation(image!, 0.2)!
let parameters = ["name": rname] //Optional for extra parameter
Alamofire.upload(multipartFormData: { multipartFormData in
//loop this "multipartFormData" and make the key as array data
multipartFormData.append(imgData1, withName: "fileset[0]",fileName: "file.jpg", mimeType: "image/jpg")
multipartFormData.append(imgData2, withName: "fileset[1]",fileName: "file.jpg", mimeType: "image/jpg")
multipartFormData.append(imgData3, withName: "fileset[2]",fileName: "file.jpg", mimeType: "image/jpg")
multipartFormData.append(imgData4, withName: "fileset[3]",fileName: "file.jpg", mimeType: "image/jpg")
for (key, value) in parameters {
multipartFormData.append(value.data(using: String.Encoding.utf8)!, withName: key)
} //Optional for extra parameters
},
to:"mysite/upload.php")
{ (result) in
switch result {
case .success(let upload, _, _):
upload.uploadProgress(closure: { (progress) in
print("Upload Progress: \(progress.fractionCompleted)")
})
upload.responseJSON { response in
print(response.result.value)
}
case .failure(let encodingError):
print(encodingError)
}
}
Noted: multipartFormData are using append meaning it is an Array of request. you can loop and append more if needed.
let url = BaseViewController.API_URL + "uploads"
let image = info[UIImagePickerControllerEditedImage] as? UIImage
let imgData = UIImageJPEGRepresentation(image!, 0.2)!
let parameters = [
"user_id" : UserDefaults.standard.value(forKey: "userId")!
]
Alamofire.upload(multipartFormData: { multipartFormData in
multipartFormData.append(imgData, withName: "uload_data",fileName: "file.jpg", mimeType: "image/jpg")
for (key, value) in parameters {
multipartFormData.append((value as AnyObject).data(using: String.Encoding.utf8.rawValue)!, withName: key)
} //Optional for extra parameters
},
to:url)
{ (result) in
switch result {
case .success(let upload, _, _):
upload.uploadProgress(closure: { (progress) in
print("Upload Progress: \(progress.fractionCompleted)")
})
upload.responseJSON { response in
self.objHudHide()
print(response.result.value)
let jsonDict : NSDictionary = response.result.value as! NSDictionary
print(jsonDict)
if jsonDict["status"] as! String == "Success"
{
let detailDict : Dictionary = jsonDict["detail"] as! Dictionary<String,Any>
if let getTotalPrice = detailDict["total_price"]
{
self.lblTotalPrice.text = "$ \(getTotalPrice) + Free Shipping"
}
if let getTotalSize = detailDict["total_upload_size"]
{
self.lblTotalSize.text = "Total Size : \(getTotalSize)"
}
}
else
{
let alertViewController = UIAlertController(title: NSLocalizedString("Alert!", comment: ""), message:"Something Went wrong please try again." , preferredStyle: .alert)
let okAction = UIAlertAction(title: NSLocalizedString("Ok", comment: ""), style: .default) { (action) -> Void in
}
alertViewController.addAction(okAction)
self.present(alertViewController, animated: true, completion: nil)
}
}
case .failure(let encodingError):
print(encodingError)
}
}
Considering Alamofire 5.0+:
Uploading Data
let data = Data("data".utf8)
AF.upload(data, to: "https://httpbin.org/post").responseJSON { response in
debugPrint(response)
}
Uploading a File
let fileURL = Bundle.main.url(forResource: "video", withExtension: "mov")
AF.upload(fileURL, to: "https://httpbin.org/post").responseJSON { response in
debugPrint(response)
}
Uploading Multipart Form Data
AF.upload(multipartFormData: { multipartFormData in
multipartFormData.append(Data("one".utf8), withName: "one")
multipartFormData.append(Data("two".utf8), withName: "two")
}, to: "https://httpbin.org/post")
.responseJSON { response in
debugPrint(response)
}
An image through Multipart Form:
// in case of parameters dictionary let's just roll the keys and values later
let parameters = ["name": rname] //var parameters: [String: Any] = [:]
AF.upload(multipartFormData: { multipartFormData in
for (key,value) in parameters {
multipartFormData.append((value as! String).data(using: .utf8)!, withName: key)
}
guard let image = photo else { return }
let jpegData = image.jpegData(compressionQuality: 1.0)
multipartFormData.append(Data((jpegData)!), withName: "photo")
}, to: "https://httpbin.org/post")
.responseJSON { response in
debugPrint(response)
}
I was having some troubles uploading an image file with Alamofire 5.
My solution looks like this:
let parameters: [String: String] = ["user_id": "1"]
AF.upload(multipartFormData: { multipartFormData in
for (key, value) in parameters {
multipartFormData.append(value.data(using: .utf8)!, withName: key)
}
if let jpegData = UIImageJPEGRepresentation(image, 1.0) {
multipartFormData.append(jpegData, withName: "image", fileName: "image", mimeType: "image/jpeg")
}
}, to: "http://example.com/upload-image")
.authenticate(username: "username", password: "password") // had basic auth
.response { response in
if response.response?.statusCode == 200 {
print("OK. Done")
}
}
after doing some quick cleanup on versions above, this one would be the snippet that I always reuse, where the Endpoints.uploadProfileImage() is just the url.
func uploadPhoto(media: UIImage, params: [String:String], fileName: String){
let headers: HTTPHeaders = [
"Content-type": "multipart/form-data"
]
AF.upload(
multipartFormData: { multipartFormData in
multipartFormData.append(media.jpegData(
compressionQuality: 0.5)!,
withName: "upload_data",
fileName: "\(fileName).jpeg", mimeType: "image/jpeg"
)
for param in params {
let value = param.value.data(using: String.Encoding.utf8)!
multipartFormData.append(value, withName: param.key)
}
},
to: Endpoints.uploadProfileImage(),
method: .post ,
headers: headers
)
.response { response in
print(response)
}
}
user_photo is key for dic
swift_file.jpg is value for value
Write the same withName is key
Write the same fileName is value
call the UploadImage(Image)
func UploadImage(img:UIImage) {
let urlfinal = “ananda.profile.php";
let parameters = ["user_id":"531", "user_photo”: "swift_file.jpg"]
Alamofire.upload(multipartFormData: { (multipartFormData) in
multipartFormData.append(UIImageJPEGRepresentation(img, 1)!, withName: "user_photo", fileName: "swift_file.jpeg", mimeType: "image/jpg")
for (key, value) in parameters {
multipartFormData.append(value.data(using: String.Encoding.utf8)!, withName: key)
}
print(multipartFormData)
}, to:urlfinal)
{ (result) in
switch result {
case .success(let upload, , ):
upload.uploadProgress(closure: { (progress) in
})
upload.responseJSON { response in
print(response)
}
case .failure( _): break
}
}
}