Сохранение информации об имени пользователя на сервере вместо 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!);
            }
        }
    }


}

Могу я спросить вас об одном, чего я не поняла в вашем вопросе. Как именно вы сохраните учетные данные для входа на сервер? Я имею в виду, если вы сохраните учетные данные для входа на сервер, как вы будете аутентифицировать доступ пользователей к этим сохраненным учетным данным?

Другие вопросы по тегам