Search code examples
swiftfirebasecocoa-touchuiviewcontrolleralamofire

Alamofire request or Firebase query is not working in a non UIViewController Class


Imperial trying to perform a request to a website using alamofire and my problem is the following:

When I use the corresponding code in an ViewController cocoaTOuch class viewDidLoad() function everything works fine.(here is the code)

super.viewDidLoad()
    let loginActionUrl = url

    do{
        let parameters = [
            "p_user":user,
            "p_password": password
        ]

        AF.request(loginActionUrl, method: .post, parameters: parameters).responseJSON
            {response in
                if let header = response.response?.allHeaderFields as? [String: String],
                    let responseUrl = response.request?.url{
                    let sessionCookies = HTTPCookie.cookies(withResponseHeaderFields: header, for: responseUrl)

                    ......

If I repeat the same code inside a private function on a swift (non cocoa touch) class, then,I have no response, While debugging it tries to perform the request task twice and then jumps out of the {response in code block.

The code is the following:

 private func checkInWithAeA(withLogIn: String, password: String) -> (Bool){
    var companyUSerRecognized: Bool = false
    var startIndex: String.Index!
   let loginActionUrl = url
    do{
    let parameters = [
        "p_user" : withLogIn,
        "p_password": password
    ]


    AF.request(loginActionUrl, method: .post, parameters: parameters).responseJSON
        {response in

            if let header = response.response?.allHeaderFields as? [String: String],
                                    let responseUrl = response.request?.url{
                let sessionCookies = HTTPCookie.cookies(withResponseHeaderFields: header, for: responseUrl)
                companyUSerRecognized = true
......

I don't now what is happening but is the second time I have the same problem. What I'm dong is trying to avoid to set up to much code in the viewController using other support classes, following best practices, but I already tried to do this with firebase, and I have the same problem, the query to the database only worked in UIViewcontroller classes (in certain) and now is the same, I am not able to obtain any result when I execute the code in the clean swift file.

Is there any kind of limitation on this. Why I cannot do anything like an alamofire request or a firebase query to the realtime database out of a UIViewController class?

Here I add some information:

  var myConnectionController: ConnectionController = ConnectionController()
                let (companyUSerRecognized, error) = myConnectionController.chekUserIDandPassWord(forTheCompany: self.companyName, logInName: self.companyLogIn, password: self.companyPassword)

This call to the ConnectionController class (that is a swift plain class) asks for a connexion to a web page. If the response is good, then a true is obtained and the process is continued.

The function called has a switch statement:

 public func chekUserIDandPassWord(forTheCompany: String, logInName: String, password: String) -> (Bool, String){
    var companyUSerRecognized: Bool!
    var error: String!

    switch forTheCompany {
    case "(AEA)":
        companyUSerRecognized = checkInWithAeA(withLogIn: logInName, password: password)
        break

.....

This is what calls Check in With AeA. (The function I just mentioned before). What I want to is get the cookies of the connection in return check them and if they are good, true is returned.

I already have done this in the viewDidLoad() function of a ViewController, In fact I can parse the response with SwiftSoup, etc. But If I do it this way I am not able to do it.

Thanks again


Solution

  • I finally made up the solution by reviewing some bibliography. I did not notice that, any alamofire call opens a pipeline. That is, we are obviously talking about asynchronous operations. There are two ways to handle with this kind of operations in swift. One is the use of future objects. This option allows the continuation of the execution by substituting the results from the async call when they are ready. Depending on the situation this is not so good. The other is to make the execution wait for the response of the async call. This is done with a closure. I took this lastoption.

    The closer is to be performed by using a completion handler function that is called at the end of the async call block to return any value you need from the async call. In this case. This is what I called completion

    private func checkInWithAeA(completion: @escaping (Bool)-> Void){
        let loginActionUrl = url1
        let postLoginUrl = url2
       let parameters = [
           "p_user" : logInName,
           "p_password": password
       ]
    
        AF.request(loginActionUrl, method: .post, parameters: parameters).responseData
                   {(response) in
                    if let header = response.response?.allHeaderFields as? [String: String],
                    let responseUrl = response.request?.url{
                    let sessionCookies = HTTPCookie.cookies(withResponseHeaderFields: header, for: responseUrl)
                        let cookieToSend = sessionCookies[0]
    

    //Debug print(cookieToSend) AF.session.configuration.httpCookieStorage?.setCookie(cookieToSend) completion(true) }else{ completion(false) } } }

    That's it. Hope it helps

    BTW. I think that this is the same problem with the firebase queries.

    Thanks!