user10281448
user10281448

Reputation:

Constructors in Swift?

In Java we can use constructors in order to pass initial values into a class. Is this possible in swift?

For example, in the line below I am trying to add an object, which should include all the values you can see in the function that is within it, into an array called arrayOfMedia.

self.arrayOfMedia.append(Media().getUsersMedia(image: image!, postNum: anyPosts.key, userID: user))

I cannot do this however and get the error below.

Cannot convert value of type '()' to expected argument type 'Media'

Upvotes: 1

Views: 4094

Answers (2)

GetSwifty
GetSwifty

Reputation: 7756

For what it's worth, in this case I would use enums to wrap your media types.

enum MediaType {
    case image(UIImage)
    case video(Data) 
}

Then you have Type safe access without requiring optionals:

struct Media {
    let postKey: Int
    let userId: Int
    let mediaType: MediaType
}

let video = Media(postKey: 1, userId: 2, mediaType: .video(dataVariable))
let image = Media(postKey: 2, userId: 3, mediaType: .image(imageVariable))

Upvotes: 1

MadProgrammer
MadProgrammer

Reputation: 347314

I do not want to have to initialize the class as the values going into it vary (sometimes a video and sometimes a image)

Okay, so that makes no sense, you have a class which is a container for some data, some of which is optional (either you have an image or a video), why not supply two different initialisers for the two different use cases ... just like you would in Java?

There's a few ways you "might" achieve this, this is just one...

class Media {
    var image: UIImage?
    var video: Data?
    let postKey: Int
    let userId: Int

    internal required init(postKey: Int, userId: Int) {
        self.postKey = postKey
        self.userId = userId
    }

    convenience init(image: UIImage, postKey: Int, userId: Int) {
        self.init(postKey: postKey, userId: userId)
        self.image = image
    }

    convenience init(video: Data, postKey: Int, userId: Int) {
        self.init(postKey: postKey, userId: userId)
        self.video = video
    }
}

Also, note, you could have simply provided a single initialiser, something like...

init(image: UIImage? = nil, video: Data? = nil, postKey: Int, userId: Int) {...}

but this doesn't constraint the user to one or the other type (they can still pass nil for both values)

Another approach might be to make use of a protocol to describe the basic/common properties of Media and then implement the different requirements (directly as structs or classs or indirectly as additional protocols)

For example...

protocol Media  {
    var postKey: Int { get }
    var userId: Int { get }
}

struct VideoMedia: Media {
    let postKey: Int
    let userId: Int
    let video: Data
}

struct ImageMedia: Media {
    let postKey: Int
    let userId: Int
    let image: UIImage
}

Upvotes: 3

Related Questions