I'm beginner in iOS swift.
I have a problem: when I do a network request, the compiler executed the code below without waiting the server response.
func callingRiderLoginCopy(userID: String, Password:String, completeCode: Int) {
print("I am in callingRiderLoginCopy And Complete verification Code is \(completeCode)")
let parameters : [String : Any] = ["userId": userID, "password": Password, "verificationCode": completeCode]
guard let url = URL(string: "\(Constents.baseURL)/rider/logIn") else {
print("Invalid URL")
return
}
AF.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default)
.responseJSON { response in
switch response.result {
case .success:
if let result = response.data {
do {
let resultIs = try JSONDecoder().decode(RiderLoginCopy.self, from:result)
self.riderSuc = resultIs.success // Strore the success state in riderSuc
print("Data is riderSuc ** \(self.riderSuc)")
if let results = resultIs.user {
print("This data came from RiderLoginCopy API : \(resultIs)")
self.setToken = KeychainWrapper.standard.set(resultIs.token!, forKey: "token")
self.retrivedToken = KeychainWrapper.standard.string(forKey: "token")!
print("Retrived Token ::: \(self.retrivedToken)")
}
} catch {
print(error)
}
}
case .failure(let error):
print(error)
}
}
}
#IBAction func verifyAct(_ sender: UIButton) {
let userId = enteredUserID
KeychainWrapper.standard.string(forKey: "Password")!
let password = enteredPassword
KeychainWrapper.standard.string(forKey: "UserID")!
let completeCode:Int = Int(textField1.text! + textField2.text! + textField3.text! + textField4.text!)!
self.callingRiderLoginCopy(userID: userId, Password: password, completeCode: completeCode)
if self.riderSuc == 1 {
let storyboard = UIStoryboard(name: "Rider", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "signin2VC") as! SignIn2VC
vc.verifyCode = completeCode
self.navigationController?.pushViewController(vc, animated: true)
}else{
print("Plese Try Try again RiderSuc is not equal to 1 !: ")
}
}
Use a closure completionHandler: parameter in your function definition of type (String?) -> Void to know when the response is received and then proceed with the rest of the code.
Modify your function from:
func callingRiderLoginCopy(userID: String, Password: String, completeCode: Int) {
To this:
func callingRiderLoginCopy(userID: String, Password:String, completeCode: Int, completionHandler: #escaping (String?) -> Void) {
And return the retrivedToken when it's received successfully and return nil when it's not.
And when you call this method modify your call from this:
self.callingRiderLoginCopy(userID: userId, Password: password, completeCode: completeCode)
To this:
self.callingRiderLoginCopy(userID: userId, Password: password, completeCode: completeCode) { token in
// Do stuff related to token
}
Related
I am having an issue with posting data using Alamofire. I am making a comment box. I grab user data from the server and post his comment using his information with his comment on the article id, but when I post it sends no information to the server! I see only empty data.
The user data are successfully loaded from the server and I can see it in the console using the print accountDetails but after posting nothing is shown!
Breakpoint gives valid data too!
My code:
class DetailsViewController: UIViewController {
var data: JSON?
var userData = [JSON]()
var accountDetails = ["name": "", "email": "", "phone": ""]
#IBOutlet weak var CommentTableView: UITableView!
#IBOutlet weak var CommentTXTField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
getUserData()
print("Account:\(accountDetails)")
if let id = Helper.getUserId() {
ContactBtn.isHidden = false
} else {
ContactBtn.isHidden = true
}
}
#IBAction func AddCommentBTN(_ sender: Any) {
let commentTXT = CommentTXTField.text
print(commentTXT!)
let name = self.accountDetails["name"]
let mobile = self.accountDetails["phone"]
let email = self.accountDetails["email"]
let articleId = data!["id"].string!
API.AddComment(articleId: articleId, name: name!, email: email!, phone: mobile!, message: commentTXT!) { (error: Error?, success: Bool) in
if success {
print("Registerd Successfuly")
} else {
print("Faile To Comment")
}
}
}
func getUserData() {
guard let UserId = Helper.getUserMob() else { return }
let url = "https://site.co/apis/getprofile.php?mob=" + UserId
AF.request(url).validate().responseJSON { [self] response in
switch response.result
{
case .failure(let error):
print(error)
case .success(let value):
let json = JSON(value)
if let id = json["data"]["id"].string {
print("id: \(id)")
}
self.accountDetails["name"] = json["data"]["name"].string
self.accountDetails["email"] = json["data"]["email"].string
self.accountDetails["phone"] = json["data"]["phone"].string
}
}
}
}
API.AddComment function
class func AddComment(articleId: String, name: String, email: String, message: String, completion: #escaping (_ error: Error?, _ success: Bool)->Void){
let url = URLs.AddComment
let parameters = [
"article_id": articleId,
"name": name,
"email": email,
"message": message
]
AF.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default , headers: nil)
.validate(statusCode: 200..<300)
.responseJSON { response in
switch response.result
{
case .failure(let error):
completion(error, false)
print(error)
case .success(let value):
let json = JSON(value)
if let id = json["data"]["id"].string {
print("id: \(id)")
completion(nil, true)
}
}
}
}
I have a Login view that asks for a card and password. I consult an API and if the entered data is correct, it sends me a JSON like this. Which return has the button method? How do I send that data to the other view? I occupy Alamofire 5.0 and have my Model class.
#IBAction func myButtonIngresarAction(_ sender: Any) {
guard let carnet = self.txtCarnet.text else {return}
guard let contrasena = self.txtPassword.text else {return}
let ingresologinmodel = IngresoLoginModel(usuario: carnet, password: contrasena)
self.apiCall(IngresoLoginModel: ingresologinmodel){
(result) in
switch result{
case .success(let json):
print(json)
**//This is where I want to send that json with the data to the other view. ******
case .failure(let err):
print(err.localizedDescription)
}
}
}
enum ApiErros: Error {
case custom(message : String)
}
typealias Handler = (Swift.Result<Any?, ApiErros>) -> Void
func apiCall(IngresoLoginModel: IngresoLoginModel, completionHandler: #escaping Handler)
{
let header: HTTPHeaders = [
.contentType("application/json")
]
AF.request("https://url/xxxx/api/Login", method: .post, parameters: IngresoLoginModel,
encoder: JSONParameterEncoder.default, headers: header).response{ response in
debugPrint(response)
switch response.result{
case .success(let data):
do{
let json = try JSONDecoder().decode([LoginModel].self, from: data!)
print(json)
if response.response?.statusCode == 200{
completionHandler(.success(json))
}else{
completionHandler(.failure(.custom(message: "Por favor verifica tu internet")))
}
}
catch
{
print(error)
completionHandler(.failure(.custom(message: "Problemas")))
}
case .failure(let err):
print(err.localizedDescription)
}
}
}
Class model
struct LoginModel: Codable {
let idEmpleado: Int
let Nombre: String
let CodEmpleado: String
let password: String
let idPerfil: Int
let activo: Int
let Descripcion: String
let idRegion: Int
let correo: String
}
This is the json that the Api sends me the data changes them for these example
{
"idEmpleado": 1,
"nombre": “test”,
"codEmpleado": “000000”,
"password": “123”,
"idPerfil": 4,
"activo": 1,
"Descripcion": “test”,
"idregion": 1,
"correo": “test#test.com"
}
many way like create a variable to save this json in OtherViewController and call, self?.otherViewController.json = json
https://learnappmaking.com/pass-data-between-view-controllers-swift-how-to/
use didSet
var page = [Datas]() {
didSet {
self.myVariable = page[0].date!
}
}
typealias Handler = (Swift.Result <[LoginModel]?, ApiErros>) -> Void
#IBAction func myButtonIngresarAction(_ sender: Any) {
guard let carnet = self.txtCarnet.text else {return}
guard let contrasena = self.txtPassword.text else {return}
let ingresologinmodel = IngresoLoginModel(usuario: carnet, password: contrasena)
self.apiCall(IngresoLoginModel: ingresologinmodel){
(result) in
switch result{
case .success(let json):
print(json)
//Here is that I do not know how to send it to the other controller all the json
let viewControllerB = HomeMenuViewController()
viewControllerB.datosPersonales = json!
self.navigationController?.pushViewController(viewControllerB, animated: true)
case .failure(let err):
print(err.localizedDescription)
}
}
}
second controller
class HomeMenuViewController: UIViewController {
#IBOutlet weak var mylabel: UILabel!
var datosPersonales = [LoginModel]()
override func viewDidLoad() {
super.viewDidLoad()
print("***************")
print(datosPersonales)
print("***************")
}
}
I am making my first attempt at using Realm in Swift. I have my model setup and I successfully receive the response using Alamofire and I map it to the object. I am then attempting to store the data in realm. It creates the object, but the values are the default values and not what is received from the backend. What am I missing? Here's the model:
import Foundation
import ObjectMapper
import RealmSwift
#objcMembers class LoginResponseModel: Object, Mappable {
dynamic var status = ""
dynamic var id = UUID().uuidString
dynamic var userId = 0
dynamic var authToken = ""
required convenience init?(map: Map) {
self.init()
}
convenience init(status: String, userId: Int, authToken: String) {
self.init()
self.status = status
self.userId = userId
self.authToken = authToken
}
override static func primaryKey() -> String? {
return "id"
}
func mapping(map: Map) {
status <- map["status"]
userId <- map["user_id"]
authToken <- map["auth_token"]
}
}
Here is where I attempt to save it:
APIHelper.shared.login(username: username!, password: password!, success: { (result) in
if let login = result {
if (login.status != "failed") {
let userId = login.userId
let authToken = login.authToken
UserDefaults.standard.setValue(String(userId), forKey: "USERID")
UserDefaults.standard.setValue(authToken, forKey: "AUTHTOKEN")
UserDefaults.standard.synchronize()
vc.modalPresentationStyle = .fullScreen
do {
let realm = try! Realm()
try realm.write {
realm.add(login)
}
} catch(let error) {
print(error)
}
InstanceID.instanceID().instanceID { (result, error) in
if let error = error {
print(error)
} else if let result = result {
self.sendToken(userId: String(userId), authToken: authToken, fcmToken: result.token)
}
}
self.present(vc, animated: true, completion: nil)
}
}
Any ideas?
API call:
public func login(username: String, password: String, success: #escaping(_ response: LoginResponseModel?) -> Void, failure: #escaping(_ error: Error?) -> Void) {
let url = "\(baseUrl)appLogin"
AF.request(url, method: .post, parameters: ["emailOrPhone": username, "password": password]).responseString { response in
print(type(of: response).self)
switch response.result {
case .success(let json):
let resp = LoginResponseModel(JSONString: json)
success(resp)
case .failure(let error):
failure(error)
}
}
}
I get the object here:
let login = realm.objects(LoginResponseModel.self).first
Value of object:
status = ""
id = "1820A5D4-A714-4774-9707-4709ED39B570"
userId = 0
authToken = ""
How can I reflect the data from the JSON Dictionary using Alamofire to perform validation to check whether the passcode entered is valid or not to my UI View Controller. I already got a Successful result in getting data from the API but I don't know how can my view controller read the values from the API to validate the passcode entered. Please help me.......
APIService
class APIService
{
let eventAPIKey: String
let eventBaseURL: URL?
//static let kEventID = "id"
init(APIKey: String)
{
self.eventAPIKey = APIKey
eventBaseURL = URL(string: BASE_URL)
}
func validatePasscode(passcode: String, completion: #escaping (Event?) -> Void)
{
if let passcodeURL = URL (string: "\(PASSCODE_CHECKER_URL)/\(passcode)") {
Alamofire.request(passcodeURL, method: .get).responseJSON { (response) in
switch response.result{
case .success:
if let passcodeJSON = response.result.value {
print(passcodeJSON)
completion(passcodeJSON as? Event)
}
case .failure(let error):
print("\(error)")
}
}
}
}
}
ViewController
func validateEventPasscode(){
let api = APIService(APIKey: passcode)
api.validatePasscode(passcode: passcode) { (event) in
if let eventDetails = self.event {
self.event = eventDetails
self.view.squareLoading.stop(0.0)
self.performSegue(withIdentifier: "showEventDashboard", sender: self)
self.enteredEventCode.text = ""
}
I have a problem with a webService call.
The problem is that when I call the service, and debug code, and print log in console, I'm sure my webService is only called once (log print once in console), but my request is apparently sent twice to the server and I have duplicate data in the list.
I know that it's not a server-side problem because it only happens on IOS (not Android).
Here is my code for call services:
public class PersistencyManager {
public func SendPostHttpRequest(baseURL: String, parameter: [String:Any], content: String, closure:#escaping ((_ success:JSON,_ error:NSError?) -> Void)) {
let manager = Alamofire.SessionManager.default
debugPrint("Request parameter ------>",parameter)
debugPrint(" Service URL -------> \(baseURL)")
if let url = URL(string: baseURL) {
var urlRequest = URLRequest(url: url)
urlRequest.setValue("text/html; charset=utf-8", forHTTPHeaderField: "Content-Type")
urlRequest.setURLEncodedFormData(parameters: parameter)
manager.request(urlRequest).responseJSON { response in
switch response.result {
case .success(let JSON) :
debugPrint("get Json response ---> \((JSON)) ")
closure(JSON,nil)
case .failure(let error):
closure(nil,error as NSError)
debugPrint("get error ---> \((error.localizedDescription)) ")
}
}
}
}
}
class LibraryAPI {
static let shareInstance : LibraryAPI = { LibraryAPI() }()
private let persistencyManager : PersistencyManager
init() {
persistencyManager = PersistencyManager()
}
func GetPostResponse(baseURL : String,parameters:[String:Any],contentType: String,closure:#escaping ((_ success:PersistencyManager.JSON,_ error:NSError?) -> Void)) {
persistencyManager.SendPostHttpRequest(baseURL: baseURL, parameter: parameters, content: contentType, closure: { success, error in
closure(success, error)
})
}
}
class TransactionAPI: TransactionProtocol {
static let shareInstance: TransactionAPI = {TransactionAPI()}()
func AddNewManagerRequest(_ parameter: [String : Any], closure: #escaping (([String : Any]?, NSError?) -> Void)) {
let url = Constants.BaseURL + Constants.K_NEWREQPORTERAGE
LibraryAPI.shareInstance.GetPostResponse(baseURL: url, parameters: parameter, contentType: "JSON", closure: {success,error in
var response: [String:Any]?
if let json = success as? [String: Any] {
response = json
}
closure(response, error)
})
}
}
class AddNewOrderViewController: MainViewController {
private func RegisterForNewPorterageRequest() {
let time = Utilities.shareInstance.GetSystemTime()
guard let userID = UserDefaults.standard.value(forKey: "user_id") as? String else {
return
}
StartActivity(activityColor: Constants.ACTIVITY_COLOR)
let token = TokenCreator.shareInstance.CreateTokenWithUserID(userID: userID, methodName: Constants.M_NEWREQUESTPORTERAGE)
request.tok = token
request.time = time
request.user_id = userID
let jsonModel = Utilities.shareInstance.GetJsonForm(objectClass: request)
TransactionAPI.shareInstance.AddNewManagerRequest(jsonModel, closure: {[weak self] success,error in
guard let strongSelf = self else{
return
}
if error != nil {
OperationQueue.main.addOperation {
strongSelf.StopActivity()
strongSelf.CreateCustomTopField(text: Constants.serverError, color: Constants.ERROR_COLOR)
}
}
else {
if let response = success {
debugPrint("add request service call once")
if let status = response["status"] as? String {
if status == "succ" {
OperationQueue.main.addOperation {
strongSelf.presentResultAlert()
}
}else {
OperationQueue.main.addOperation {
strongSelf.StopActivity()
strongSelf.CreateCustomTopField(text: Constants.send_data_error, color: Constants.ERROR_COLOR)
}
}
}
}
}
})
}
}
After adding log to server, I made sure my request was sent twice to server.
All console log print once in console.
I don't know when I call service twice, and why my request was sent twice to the server.
I don't understand how the log be displayed once, but the service has been called twice?
Any help appreciated.
It's really confusing, but it works perfectly with this method.
i have this method in persistencyMangerClass and i using this method instead SendPostHttpRequest.What really is the difference between these two methods. :|
public func SendMultiPartRequestWith(baseUrl: String, parameters: [String : Any],closure: #escaping ((_ success:JSON,_ error:NSError? ) -> Void)){
let manager = Alamofire.SessionManager.default
manager.session.configuration.timeoutIntervalForRequest = 30
manager.session.configuration.timeoutIntervalForResource = 15
debugPrint(" Service URL -------> \(baseUrl)")
debugPrint("Request parameter ------>",parameters)
let headers: HTTPHeaders = [
"Content-type": "multipart/form-data"
]
manager.upload(multipartFormData: { (multipartFormData) in
for (key, value) in parameters {
if let data = value as? Data {
let fileName = (key as String) + ".jpg"
let mimType = (key as String) + "/jpg"
multipartFormData.append(data, withName: key as String, fileName: fileName, mimeType: mimType)
}
else {
if let v = value as? String {
multipartFormData.append("\(v)".data(using: String.Encoding.utf8)!, withName: key as String)
}else {
multipartFormData.append("".data(using: String.Encoding.utf8)!, withName: key as String)
}
}
}
}, usingThreshold: UInt64.init(), to: baseUrl, method: .post, headers: headers) { (result) in
switch result{
case .success(let upload, _, _):
upload.responseString { response in
if let err = response.error{
closure(nil, err as NSError)
return
}
if let JSON = response.result.value {
closure(JSON, nil)
}
}
case .failure(let error):
closure(nil, error as NSError)
}
}
}