3

Within my app, I have multiple UIView subclasses that depend on a model. Each of the classes adopting 'Restorable' protocol which holds the superclass of the model. Each sub-model describes the specific UIView not-common properties.

// Super-model public protocol StoryItem { var id: Int64? { get } } // Parent protocol public protocol Restorable: AnyObject { var storyItem: StoryItem? { get set } } // Specific protocol public struct TextItem: StoryItem { public var id: Int64? public var text: String? } // Not complling class ResizableLabel: UILabel, Restorable { var storyItem: TextItem? } 

I'm getting the following compiler error:

*Type 'ResizableLabel' does not conform to protocol 'Restorable'* 

The only way I can make it compile is by changing ResizableLabel to

// Works class ResizableLabel: UILabel, Restorable { var storyItem: StoryItem? } 

Is there any way to conform to protocol subclass? it'll make the Init process much cleaner. Thank you for your help!

2
  • Hey @matt, thank you for replying. I've updated the code to be clearer. Also, I changed TextItem to be struct and not protocol. In my app, I can create labels, images. stickers etc'. Each of them being constructed using a different model. But all the models have a superclass-model that share the common properties. When I'm adding a model to the UIView-subclass, let's say label. I want to specify that this object gets his data from the TextModel (that's why I changed the storyItem class to TextItem. Commented Jun 29, 2019 at 1:24
  • @matt Right now, when I'm creating a label object, for example, I'm creating TextItem and than assign it to the storyItem (the most bottom code line which works), and every time I want to access it I need to cast it, which I'm trying to avoid Commented Jun 29, 2019 at 1:26

1 Answer 1

6

Change

public protocol Restorable: AnyObject { var storyItem: StoryItem? { get set } // adopter must declare as StoryItem } 

to

public protocol Restorable: AnyObject { associatedtype T : StoryItem var storyItem: T? { get set } // adopter must declare as StoryItem adopter } 

Now your code compiles. Full example:

public protocol StoryItem { var id: Int64? { get } } public protocol Restorable: AnyObject { associatedtype T : StoryItem var storyItem: T? { get set } } public struct TextItem: StoryItem { public var id: Int64? public var text: String? } class ResizableLabel: UILabel, Restorable { var storyItem: TextItem? // ok because TextItem is a StoryItem adopter } 
Sign up to request clarification or add additional context in comments.

9 Comments

Added comments that explain the difference between what you were saying and what you wanted to say.
Hey @matt, small follow-up question. Let's say I have a UIView which has stickers, images, labels as subviews among other classes. and I want to get only the subviews that adopt 'Restorable' subviews. so I tried something like: let restorableSubviews = view.subviews.compactMap({$0 as? (Restorable & UIView)}). But I'm gettings compile error: Protocol 'Restorable' can only be used as a generic constraint because it has Self or associated type requirements.|| Do I need to cast them differently?
Btw if you think I need to post another question, let me know and I'll do it immediately.
In order to satisfy your requirement in this question, we had to make Restorable a generic constraint. Now it cannot be used as a type. The simplest solution is to declare an empty protocol that only Restorable adopts, and use that as your type name (though you'll then have to cast down later). But that isn't the only solution; search on that error and you'll find that this has been thoroughly discussed on Stack Overflow, so there's no point asking a new question - it will be a duplicate.
Thank you for replying! Should I do that for each object (Label/Image/Sticker)? Or It's one protocol to rule them all?
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.