I am learning protocol oriented approaches and I am facing below issue when adding access modifiers.
I have an enum for mode type. It can be changed.
public enum ModeType: String {
case Smart = "Smart"
case Easy = "Easy"
}
I have created a protocol like below.
protocol Device {
var deviceID: String { get }
var title: String { get }
var currentMode: ModeType { get set }
}
And below class conforms to the Device protocol.
class DeviceList: Device {
public private(set) var currentMode: ModeType
public private(set) var deviceID: String
public private(set) var title: String
init(deviceID: String, title: String, currentMode: ModeType, waterLevel: String, humidityLevel: String) {
self.deviceID = deviceID
self.title = title
self.currentMode = currentMode
}
}
Issue is public private(set) var currentMode: ModeType
but below works
public internal(set) var currentMode: ModeType
What am I misunderstanding here can anyone explain?
Related
I am trying to set up some protocols for mocking and previews, ran into and solved a conformance issue on the Message struct, but I could use help understanding why I needed an associatedtype.
public protocol ChatUser: Identifiable {
var id: String { get }
var avatar: UIImage { get }
}
public struct User: ChatUser {
public let id: String
public let avatar: UIImage
}
public protocol ChatMessage: Identifiable {
var id: String { get }
var date: Date { get }
var text: String { get }
var user: any ChatUser { get }
}
public struct Message: ChatMessage {
public let id: String
public let date: Date = Date.now
public let text: String
public let user: User
}
Xcode was telling me that Type 'Message' does not conform to protocol 'ChatMessage' and suggests adding user: ChatUser when I already have user: User where User does in fact conform to ChatUser.
I solved this by adding an associatedtype to ChatMessage:
public protocol ChatMessage: Identifiable {
associatedtype MessageAuthor: ChatUser
var id: String { get }
var date: Date { get }
var text: String { get }
var user: MessageAuthor { get }
}
I'm at a loss as to why any ChatUser does not work here but an associatedtype of ChatUser does.
What is the difference between { } and = when assigning an enum to a variable in Swift?
Why would you say var type: ItemType { .recipe } over var type: ItemType = .video.
Does the {} indicate that it is a computed property?
Also, is the { get } needed after the type in the protocol?
enum ItemType: String, Decodable {
case video
case recipe
}
protocol Item: Decodable {
var type: ItemType { get }
var title: String { get }
var imageURL: URL { get }
}
struct Video: Item {
var type: ItemType = .video
var title: String
var imageURL: URL
var url: URL
var duration: String
var resolution: String
}
struct Recipe: Item {
var type: ItemType { .recipe }
var title: String
var imageURL: URL
var text: String
var ingredients: [String]
}
Does the {} indicate that it is a computed property?
Yes.
Also, is the { get } needed after the type in the protocol?
To specify that the property, whether it be computed or stored, needs to support at least a getter. The setter is optional.
I want a collection of a protocol type: in this case I want a variable "party" to be an array of type GameCharacter so I can put all things that conform to GameCharacter inside it.
the code below produces the following error:
Protocol 'GameCharacter' can only be used as a generic constraint because
it has Self or associated type requirements
what's the problem here? how to do it right?
protocol GameCharacter: Identifiable {
var name: String {get}
var maxHealt: Int {get}
var healt: Int { get set }
}
struct Warrior: GameCharacter, Fighter {
var name: String
var maxHealt: Int
var healt: Int
var armor: Armor
var weapon: Weapon
var resistence: Int
var id: String {
return name
}
}
var party: [GameCharacter] <--- error
You should not inherit your protocol from Identifiable (which has generics) in this case, instead add id explicitly and then below (simplified) is compilable
protocol GameCharacter {
var id: String { get } // << here !!
var name: String {get}
var maxHealt: Int {get}
var healt: Int { get set }
}
struct Warrior: GameCharacter {
var name: String
var maxHealt: Int
var healt: Int
var resistence: Int
var id: String { // << here !!
return name
}
}
I believe Identifiable is a protocol with associated type. Unfortunately, Swift does not support what you are trying to achieve, yet.
Please refer Swift associated types and protocol inheritance and How to use generic protocol as a variable type for discussions around this topic. These links discuss on possible solutions as well.
I have seen this in some videos on Youtube.
class Student {
private var _name: String!
private var _studentID: Int!
var name: String {
return _name
}
var studentID:Int {
return _studentID
}
init(name: String, studentID: Int) {
self._name = name
self._studentID = studentID
}
}
Any reason why they are doing this (adding _name and _studentID) instead of:
class Student {
private var name: String!
private var studentID: Int!
init(name: String, studentID: Int) {
self.name = name
self.studentID = studentID
}
}
Thank you very much.
The first examples are essentially creating properties that are publicly readable but privately writable.
The second set of code does not do the same thing as the first set.
The proper way to write this code is:
private (set) var name: String // no need for the !
private (set) var studentID: Int // no need for the !
init(name: String, studentID: Int) {
self.name = name
self.studentID = studentID
}
This makes the properties readable by outside users but only settable by the class. This is what the 1st set of code implements but in a much more verbose and needless manner.
The use of underscore is just a naming convention carried over from Objective-C when creating private instance variables.
Personally, I'd avoid videos and tutorials that use the 1st set of code.
using static var and instance var as the variable same name in Swift that will occur compiler error. why?
example:
protocol naming {
static var firstName: String { get }
var firstName: String { get }
}
class Employee: NSObject, naming {
class var firstName: String {
return "MyName"
}
var firstName: String {
return Employee.firstName
}
}
It's a bug. (One of several connected with static variables in protocols.) And in Swift 2.0, it's fixed.