Сохранение информации об имени пользователя на сервере вместо NSDefaults (iOS)
У меня есть сервер для хранения имени пользователя и пароля в моем приложении. При тестировании приложения у меня все было сохранено на устройстве локально с использованием NSDefaults, но теперь, когда приложение близко к тому, чтобы быть полностью запущенным, я пытаюсь сохранить их на сервере, так как это безопаснее для информации пользователя.
Когда я сохранил его в NSDefaults, это была простая и короткая работа. Однако теперь я пытаюсь отправить данные на сервер и продолжаю получать ошибки сборки. Что мне нужно изменить, чтобы это работало? Я не до конца понимаю, как работает POST и GET? Благодарю. Использование Swift 2 на данный момент, а не мой выбор, я предпочитаю 3, но мой начальник пока не позволяет нам обновлять его.
Текущая ошибка поступает из раздела POST USER DATA TO SERVER, где xcode утверждает, что userNmeTxt не может быть преобразован в NSData. Заранее спасибо.
РЕДАКТИРОВАТЬ: Ошибка в строке 87: "Не удалось преобразовать значение типа UITextField! В ожидаемый тип аргумента NSData!"
import UIKit
class UserNameViewController: AuthorizationViewController {
@IBOutlet weak var userNameTxt: UITextField!
@IBOutlet weak var continueBtn: UIButton!
var userModel: ProfileModel!
//MARK: - SYSTEMS METHODS
override func viewDidLoad() {
super.viewDidLoad()
userNameTxt.delegate = self
userNameTxt.autocapitalizationType = .Sentences
setEnabledButton()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.navigationBarHidden = false
self.navigationItem.leftBarButtonItem = getBackButton()
self.title = ""
}
override func viewWillDisappear(animated: Bool) {
self.navigationController?.navigationBarHidden = true
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
continueBtn.layer.cornerRadius = 10
}
override func popToRoot(sender:UIBarButtonItem){
self.navigationController!.popViewControllerAnimated(true)
}
//MARK: - CHECK FOR AVALABILITY
func setEnabledButton(){
if userNameTxt.text == "" {
continueBtn.backgroundColor = UIColor.lightGrayColor()
} else {
continueBtn.backgroundColor = UIColor(colorLiteralRed: 63.0/255.0, green: 220.0/255.0, blue: 236.0/255.0, alpha: 1.0)
}
continueBtn.userInteractionEnabled = userNameTxt.text != ""
}
//MARK: - POST USER DATA TO SERVER
func postData(url: String, params: Dictionary<String, String>, completionHandler: (data: NSData?, response: NSURLResponse?, error: NSError?) -> ()) {
// Indicate download
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
let url = NSURL(string: "myPlaceholderURLgoesHere")!
// print("URL: \(url)")
let request = NSMutableURLRequest(URL: url)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
// Verify downloading data is allowed
do {
request.HTTPBody = try NSJSONSerialization.dataWithJSONObject(params, options: [])
} catch let error as NSError {
print("Error in request post: \(error)")
request.HTTPBody = nil
} catch {
print("Catch all error: \(error)")
}
// Post the data
let task = session.dataTaskWithRequest(request) { data, response, error in
completionHandler(data: userNameTxt, response: userModel, error: error)
// Stop download indication
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
// Stop download indication
}
task.resume()
}
//MARK: - SEGUE
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "toPassword"{
let controller = segue.destinationViewController as! PasswordViewController
controller.userModel = userModel
}
}
//MARK: - IB ACTIONS
@IBAction func continuePressed(sender: AnyObject) {
userModel.userNickName = userNameTxt.text!
performSegueWithIdentifier("toPassword", sender: self)
}
}
extension UserNameViewController: UITextFieldDelegate{
func textFieldDidEndEditing(textField: UITextField) {
self.setEnabledButton()
}
}
3 ответа
Есть пара вещей, которые нужно изменить.
userNameTxt
это не имя пользователя, это UITextField, содержащий имя пользователя. Текст, который вам нужен userNameTxt.text?
Если функция ожидает данных, вы должны сначала преобразовать текст в данные
let task = session.dataTaskWithRequest(request) { data, response, error in
completionHandler(data: userNameTxt.text?.data(using: .utf8), response: userModel, error: error)
Я предполагаю, что вы должны отправить данные на сервер.
Если у вас их нет, вы можете сохранить данные в доступе цепочки для ключей, см.: SO: Доступ цепочки для ключей
Чтобы устранить ошибку, отредактируйте вопрос с сообщением об ошибке и строкой кода (если это возможно).
Я бы посоветовал вам использовать Alamofire для POST/GET (REST). Чтобы использовать Alamofire вам нужны базовые знания о Cocoapods. Это лучше в долгосрочной перспективе.
ПРИМЕЧАНИЕ. При выполнении запроса возможны два исхода ошибки.
1) Неверный формат данных или ошибка с вашей стороны
2) Ошибка сервера из-за ошибки сервера со стороны сервера.
Данные могут быть отправлены с вашего устройства с помощью POST, где данные находятся в теле или заголовке запроса. Обычно это в теле (параметры в методах alamofire).
Вот пример:
import Alamofire
...
// MARK:- Login Feature - Universal Met for login
internal static func loginWith(serverUrl: String, parameters: [String: AnyObject]?, headers: [String: String]?, notificationName: String, serviceType: LoginService)
{
Alamofire.request(.POST, serverUrl, parameters: parameters, headers: headers).responseJSON
{ (response) in
print("\n Login feature - \n")
print(" Login url - \(serverUrl)\n")
print(" Login parameters - \(parameters)\n")
print(" Login notificationName - \(notificationName)\n")
print(" Login response - \(response)\n")
EXCDataParserH.parseResponseFrom(ServiceType.Login(type: serviceType),
operation: nil,
data: response.data,
notification: notificationName)
}
}
Вместо того, чтобы писать все это каждый раз, когда вы делаете запрос к серверу, попробуйте сделать следующее:
import Foundation
import SystemConfiguration
class HTTPHelper{
class func httpPostDataDic(postURL:NSURL,postString:NSString,completionHandler:@escaping (NSDictionary?, NSError?) -> Void ) -> URLSessionTask{
var responseResultData: NSDictionary = NSDictionary()
let request = NSMutableURLRequest(url:postURL as URL);
request.httpMethod = "POST";// Compose a query string
request.httpBody = postString.data(using: String.Encoding.utf8.rawValue);
print(request)
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
if error != nil
{
print("error=\(error)")
completionHandler(nil, error as NSError?)
return
}
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
if let responseString = responseString {
print("responseString = \(responseString)")
}
do {
let myJSON = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
responseResultData=myJSON!
completionHandler(responseResultData, nil)
} catch {
print(error)
}
}
task.resume()
return task
}
}
Теперь, когда вам нужно сделать запрос POST сервера, в вашем классе ViewController, сделайте следующее:
//Requesting server
func requestServer() -> Void{
let postvariable = "Value"
let url = URL(string: "your url")!
let postString = "postkey=\(postvariable)"
HTTPHelper.httpPostDataDic(postURL: url as NSURL, postString: postString) {
(responseResult, error) -> Void in
DispatchQueue.main.async {
if error != nil{
print(error ?? "unknown")
}
else{
print(responseResult ?? "unknown result")
//Parse your response
self.parseResult(result: responseResult!);
}
}
}
}
Могу я спросить вас об одном, чего я не поняла в вашем вопросе. Как именно вы сохраните учетные данные для входа на сервер? Я имею в виду, если вы сохраните учетные данные для входа на сервер, как вы будете аутентифицировать доступ пользователей к этим сохраненным учетным данным?