有没有办法访问IBAction中修改的变量?

时间:2017-11-06 22:39:25

标签: ios swift ibaction

以下是我要做的事情:

var usernameCheckerResponse : String = ""

 //This IBAction is a UITextfield that sends post request when editing is finshed.
 @IBAction func usernameChecker(_ sender: Any) {

 // perform post request with URLSession
 // post request returns url response from URLSession 
 // the value of this response is either 'usernameExists' or 'usernameAvailable'
 // usernameCheckerResponse = String(describing : response) 

}
//use modified usernameCheckerResponse variable outside the IBAction function. 
//For example like this:

   func UsernameExists () -> Bool {
   if(usernameCheckerResponse == "usernameExists"){
   return true
  } else { return false }
}

我知道IBAction只会返回一个空白,所以无论如何都会出现这个问题吗? 任何帮助和/或建议将不胜感激。

2 个答案:

答案 0 :(得分:1)

绝对是的。这是一个例子,

var usernameCheckerResponse : String = ""

 //This IBAction is a UITextfield that sends post request when editing is finshed.
 @IBAction func usernameChecker(_ sender: Any) {

 //post request
 // post request returns url response
 // usernameCheckerResponse = String(describing : response) 

}
//use modified usernameCheckerResponse variable outside the IBAction function.

func accessVariable() {
   print("\(usernameCheckerResponse")
}

请记住,这里的技巧是在变量发生变化时访问变量。要做到这一点,你需要选择某种方式来跟踪它。委派可能是最标准的方法。 See this.您必须更具体地了解为什么要更改变量,因为我需要知道使用它的是什么(委托要求您对参与者非常具体)。

我还想更具体地说明委托的工作方式。您可以指定' accessVariable()'函数在您想要修改变量的位置调用(这将始终位于两个不同的类或结构之间)。请记住,如果您只是尝试在同一个类中共享变量,则不需要使用委派。调用函数' accessVariable()'就足够了。但是,如果你希望在同一个类中发生某些事情,但你真的想控制函数完成的顺序,那么你需要使用回调。

BTW Leo,这样做会让应用程序崩溃......

答案 1 :(得分:0)

通常,您应该将IBAction函数视为 按钮等控件的连接点 你永远不会自己打电话。 如果您需要这样做,请创建另一个功能 并使用IBAction函数调用。

因为您正在使用URLSession从外部获取数据 来源,你需要知道这不会同步发生。 将调用发送到您的API并调用完成处理程序 何时返回数据。

所有这些代码都会进入您的ViewController

// Set up a reusable session with appropriate timeouts
internal static var session: URLSession  {
    let sessionConfig = URLSessionConfiguration.default
    sessionConfig.timeoutIntervalForRequest = 6.0
    sessionConfig.timeoutIntervalForResource = 18.0

    return URLSession( configuration: sessionConfig )
}


// Create an httpPost function with a completion handler
// Completion handler takes :
//   success: Bool true/false if things worked or did not work
//   value: String string value returned or "" for failures
//   error: Error? the error object if there was one else nil
func httpPost(_ apiPath: String, params: [String: String], completion:@escaping (Bool, String, Error?) -> Void) {
    // Create POST request
    if let requestURL = URL( string: apiPath ) {
        print("requestUrl \(apiPath)")
        // Create POST request
        var request = URLRequest( url: requestURL )
        request.httpMethod = "POST"

        var postVars : [String : String ] = params
        var postString = postVars.toHttpArgString()

        request.httpBody = postString.data( using: String.Encoding.utf8, allowLossyConversion: true )

        let sendTask = ViewController.session.dataTask( with: request) {
            (data, response, error) in

            if let nserror = error as NSError? {
                // There was an error
                // Log it or whatever
                completion(false, "", error)
                return
            }

            // Here you handle getting data into a suitable format

            let resultString = "whatever you got from api call"
            // Send it back to the completion block
            completion(true, resultString, nil)
        }
        sendTask.resume()
    }
}
// I assume you have a text field with the user name you want to try
@IBOutlet weak var usernameToCheck : UITextField!
@IBAction func usernameChecker(_ sender: Any) {
    guard let username = usernameToCheck.text else {
        // This is unlikely to happen but just in case.
        return
    }
    httpPost("https://someapicall", params: ["username" : username] ) {
        (success, value, error) in
        // This code gets called when the http request returns data.
        // This does not happen on the main thread.
        if success {
            if value == "usernameExists" {
                // User name already exists. Choose a different one.
                DispatchQueue.main.async {
                    // put code here if you need to do anything to the UI, like alerts, screen transitions etc.
                }
            }
            else if value == "usernameAvailable" {
                // You can use this user name
                DispatchQueue.main.async {
                    // put code here if you need to do anything to the UI, like alerts, screen transitions etc.
                }
            }
            else {
                // Unexpected response from server
            }

        }
        else {
            // Something did not work
            // alert "Unable to connect to server"
        }

    }
}

要使此代码有效,您需要:

// Syntatic sugar to convert [String:String] to http arg string
protocol ArgType {}
extension String: ArgType {}
extension Dictionary where Key: ArgType,  Value: ArgType  {
    // Implement using a loop
    func toHttpArgString() -> String {
        var r = String()
        for (n, v) in self {
            if !r.isEmpty { r += "&" }
            r += "\(n)=\(v)"
        }
        return r
    }

}