1

I have a class modelling question with Swift. I have a range of classes that each do the same task (in my example below, Decoding), but they are specialised and each produce a different type of object.

In some cases I will want to be able to talk about my Decoders generally such as getGeneralInfo() or getDecoderForIdentifier(). In other cases, such as where I am doing a decode operation, I will either instantiate the class directly or use as?.

The following code does not work because you can't use Decoder as a return type when it has an associated type.

My solution is to remove decode() from the protocol and have each class just implement its own. I then need to instantiate concrete classes directly where they are needed. This is workable but it makes me sad.

Is there any way I can rejuggle this to have the compiler enforce "all Decoders should have a decode() method according to their associatedtype"?

I have tried using a generic superclass but it requires me to provide a method body for decode(), which is pretty gnarly if your return type isn't optional.

protocol Decoder { associatedtype Model func getGeneralInfo() -> GeneralInfo func decode(sourceData: Data) -> Model } // This return type is not allowed because Decoder has an associated type func getDecoderForIdentifier(id: String) -> Decoder { if id == "mp3" { return Mp3Decoder() } if id == "wave" { return WaveDecoder() } /* ... */ } class Mp3Decoder: Decoder { typealias Model = Mp3Info func getGeneralInfo() -> GeneralInfo { let info = GeneralInfo() /* ... */ return info } func decode(sourceData: Data) -> Model { let result = Mp3Info() /* ... */ return result } } class WaveDecoder: Decoder { typealias Model = WaveInfo /* ... similar to mp3 ... */ } 
0

1 Answer 1

1

If you make Model a protocol then you can return Decoder because then it will not need associated types.

protocol Model { // ... } protocol Decoder { func getGeneralInfo() -> GeneralInfo func decode(sourceData: Data) -> Model } class Mp3Decoder: Decoder { func getGeneralInfo() -> GeneralInfo { let info = GeneralInfo() // ... return info } func decode(sourceData: Data) -> Model { let result = Mp3Info() // ... return result } } func getDecoderForIdentifier(id: String) -> Decoder { if id == "mp3" { return Mp3Decoder() } // ... } 
Sign up to request clarification or add additional context in comments.

1 Comment

Ah that's clever! I'm yet to convince myself this structure is a good idea but you've definitely solved the biggest issue I'm having, thank you.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.