coolly
coolly

Reputation: 353

How can I allow my function to accepts two different objects in swift?

I have a function which takes one argument. I wanted my function to accept two object types. How can I do it? Here is the example below:

func accept(user: Customer) {
  ...
}

It should accept Customer and Employee object reference.

accept(objRefCustomer)
accept(objRefEmployee)

Please help me in this case.

Upvotes: 8

Views: 6227

Answers (5)

user3206558
user3206558

Reputation: 392

create a protocol, and use it as argument type. protocol can be also empty, it will work anyway. Works with struct and class as well;

ex:

protocol SomeFakeProtocol {}
class SomeClass: SomeFakeProtocol { //code here }
struct SomeStruct: SomeFakeProtocol { //code here }

func someFunction(arg: SomeFakeProtocol) { //code here }

Benefits - you can allow to use only types you want to. And, sure, you can do things like this:

extension String: SomeFakeProtocol {}

Upvotes: 3

dfrib
dfrib

Reputation: 73186

Alternative to super-classing: use protocols

You needn't necessarily use a superclass for this case (if Customer and Employee are struct value types; superclass option is not possible), but can rather use the more generic approach of protocols.

Define a protocol Users which blueprints properties and methods for your Customer and Employee instances (if we let Customer and Employee conform to Users, then we promise that instances of these two structures will have accessible the blueprinted properties and methods):

protocol Users {
    var name: String { get }
    func printTypeOfUser()
}

Define the Customer and Employee structures, and their conformance to the protocol Users:

struct Customer : Users {
    let name: String
    init(name: String) { self.name = name }

    func printTypeOfUser() {
        print("Is a Customer!")
    }
}

struct Employee : Users {
    let name: String
    let id: Int
    init(name: String, id: Int) { self.name = name; self.id = id }
    
    func printTypeOfUser() {
        print("Is an Employee!")
    }
}

Now you can define a generic function where its generic, say T, is type constrained to types conforming to the protocol Users, which in this case is equivalent to the Customer or Employee types

func accept<T: Users>(user: T) {
    print("Name of user: \(user.name) [\(user.dynamicType)]")
    user.printTypeOfUser()
    
    // do something additional employee-specific if user is an employee?
    if let employee = user as? Employee {
        print("User is an employee with id: \(employee.id)")
    }
}

Example usage of this function for Employee as well as Customer instances:

let employee = Employee(name: "John", id: 1)
let customer = Customer(name: "Sarah")

accept(employee) /* Name of user: John [Employee] 
                    Is an Employee!
                    User is an employee with id: 1 */

accept(customer) /* Name of user: Sarah [Customer]
                    Is a Customer!                 */

Upvotes: 7

Horatiu
Horatiu

Reputation: 151

You don't need a super class, you can just pass an object of type AnyObject and in your function check the type of the object passed:

func accept(user: AnyObject) {
    if let usr = user as? Person {
        ...
    }
}

But if you have many types you want to pass you may want to make a protocol or a super class.

Upvotes: 1

NSNoob
NSNoob

Reputation: 5618

Instead of changing your Class structure and code base, you can use AnyObject. It will also be easier for you if, for example, in future you have to make this function accept parameters of class WaterMelon. Making all these classes inherit from a common parent class would be unnecessary overhead, not to mention hectic.

AnyObject is swift equivalent of objective c id. AnyObject is a protocol that can represent an instance of any class type.

It also has a more general counterpart, Any, which can represent any type at all (including structs and enums).

Following code will accept any class type parameter you pass:

func accept(sender : AnyObject) { //Or AnyObject? if you want to handle nil as well
      ...
    }

To access properties of the classes you pass as AnyObject, you can use type casting.

For example below code will check sender type and typecast it for you:

if let customerRef = sender as? Customer {
    // ...
    // Sender is of customer class type. Use it with customerRef that we created
    let customerName = customerRef.dynamicType.sampleNameProperty //Access a property of class Customer
    customerRef.funcOfCustomerClass() //Call a method of class Customer
}
else{
 //Sender is not of customer class type. 
//Then it must be Employee??? Handle cases for employee here.
}

Upvotes: 5

Twitter khuong291
Twitter khuong291

Reputation: 11692

You can create a super class called People of Cutomer and Employee.

Then set user as type of People:

func accept(user: People) {
  ...
}

Upvotes: 2

Related Questions