Mojtaba Yeganeh
Mojtaba Yeganeh

Reputation: 2922

swift method accept parameter if conform a protocol

i have a protocol named WebServiceProtocol and method like this :

class func executeRequest(delegate:__SOMETHING__,url:String,postParameters:[String:String],headerParameters:[String:String]){
   //Do something and call delegate
}

i want to have a conditional argument that check if input conform WebServiceProtocol Accept it.

i'm tying to write a global class function that work with every input , maybe a ViewController or NSObject class.

in java for classes we did like this :

<? extends SomeClass>

Edit enter image description here WebService.swift

import Foundation

protocol WebServiceProtocol {
    func onDataReceived(data:NSDictionary!)
    func onFailure()
}

class WebService:NSObject{

    class func executeRequest(delegate:WebServiceProtocol,url:String,postParameters:[String:String],headerParameters:[String:String]){
        if let URL: NSURL = NSURL(string: url){
            var request:NSMutableURLRequest = NSMutableURLRequest(URL:URL)
            request.HTTPMethod = "POST"
            request.HTTPBody = arrayToHttpParams(postParameters).dataUsingEncoding(NSUTF8StringEncoding)
            NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()){
                    response, data, error in
                    if error == nil {
                        if let jsonString = NSString(data: data, encoding: NSUTF8StringEncoding){
                            if let dictionary = Helper.parseJson(jsonString as String) {
                                delegate.onDataReceived(dictionary)
                                println(dictionary)
                                return;
                            }
                        }
                        println("failure !")
                        delegate.onDataReceived(nil)
                    }
                    else{
                        delegate.onFailure()
                    }
            }
        }
    }

    class func arrayToHttpParams(params:[String:String])->String{
        var mergedParams = [String]();
        for (key,value) in params {
            mergedParams.append(key+"="+value)
        }
        return "&".join(mergedParams);
    }
}

Authentication.swift

protocol AuthenticationLoginProtocol {
    func onSuccess(data:NSDictionary)
    func onFailure(data:NSDictionary)
}

class Authentication:NSObject,WebServiceProtocol{

   func attempLogin(delegate:ViewController,emial:String,password:String){

        var params = [String:String]();
        params["key1"]="value1"
        params["key2"]="value2"

        WebService.executeRequest(self, url: "", postParameters: params, headerParameters: params)

    }

    func onDataReceived(data: NSDictionary!) {

    }
    func onFailure() {

    }

}

Upvotes: 0

Views: 1898

Answers (4)

mustafa
mustafa

Reputation: 15464

You can make that method generic

class func executeRequest<T: WebServiceProtocol>(delegate: T,url:String,postParameters:[String:String],headerParameters:[String:String]) {

}

There is an article about how this approach and @Will M.'s differ each other.

Upvotes: 0

Will M.
Will M.

Reputation: 1854

If you make the input take your protocol as the parameter type, the compiler will only compile if the parameter for that function implements that protocol, like above.

import UIKit

protocol WebServiceProtocol {

}

class ViewController: UIViewController {

    @IBOutlet weak var testLabel: UILabel!

    func takeProtocolAsInput(input: WebServiceProtocol) {

    }

    func otherFunc() {
        takeProtocolAsInput(A())

        // Compile-time error: B does not conform to WebServiceProtocol
        takeProtocolAsInput(B())
    }
}

class A: WebServiceProtocol {

}

class B {

}

Upvotes: 2

J&#243;zsef Vesza
J&#243;zsef Vesza

Reputation: 4795

Update

You are trying to reference an instance in a type method. Instead of this,

WebService.executeRequest(self, url: "", postParameters: params, headerParameters: params)

write this:

WebService.executeRequest(Authentication.self, url: "", postParameters: params, headerParameters: params)

Then later in for example Authentication:

class Authentication: NSObject, WebServiceProtocol {

    // ...

    func someMethod() {
        WebService.executeRequest(self, url: "", postParameters: ["1": "2"], headerParameters: ["1": "2"])
    }

    // ...
}

Original answer

You could make a generic function with a type constraint for your protocol:

func myFunc<T: WebServiceProtocol>(input: T) {
  // input surely conforms to WebServiceProtocol
}

This way, T can be any type, as long as it conforms to the WebServiceProtocol.

For more details, see Type Constraints here.

Upvotes: 4

ABakerSmith
ABakerSmith

Reputation: 22979

@József Vesza solution is good because Xcode will let you know if you're trying to pass in an object that doesn't conform to WebServiceProtocol. However, if you want to be able to pass anything (as specified in the question) to your function you could do the following:

func myFunc(obj: Any) {
    if let webService = obj as? WebServiceProtocol {
        // Do stuff with webService...
    }
}

Upvotes: 1

Related Questions