Understanding struct initialiser if it contain private property - swift

I want to understand how initialiser work if struct contains private properties. I have following code:
struct Doctor {
var name: String
var location: String
private var currentPatient = "No one"
}
let drJones = Doctor(name: "Esther Jones", location: "Bristol")
This throws an error:
Cannot invoke initializer for type 'Doctor' with an argument list of
type '(name: String, location: String)'
My Assumption is: Default Memeberwise initialiser contains private property which can't be called from outside.
But I am confused by following code:
struct Doctor {
private var currentPatient = "No one"
}
let drJones = Doctor()
How this is working?, it is not throwing any error.

You can't use default memberwise initialiser for assigning struct's property with private access level modifier.
Your second example works, because you gave your property default value so there is no need to assign it while you're initalizing it.
If you need to assign your private property using initializer, you have to write your own
init(name: String, location: String, currentPatient: String) {
self.name = name
self.location = location
self.currentPatient = currentPatient
}

Related

Stored property without initial value prevents synthesized initializers

I declare a protocol:
protocol FullNameable {
var fullName: String {get set}
}
then adopt the above protocol for class and struct like below:
struct LectureStruct: FullNameable {
var fullName: String
}
class LectureClass: FullNameable {
var fullName: String
}
But for class I am getting error - Stored property 'fullName' without initial value prevents synthesized initializers. Why this error is not for a struct?
According to swift documentation:
All structures have an automatically generated memberwise initializer,
which you can use to initialize the member properties of new structure
instances. Initial values for the properties of the new instance can
be passed to the memberwise initializer by name
let vga = Resolution(width: 640, height: 480)
Unlike structures, class instances don’t receive a default memberwise
initializer.
In your case, you can instantiate LectureStruct with:
let lecture = LectureStruct(fullName: "Match Lecture")
In order to do the same with LectureClass you'll need to define an init method like so:
class LectureClass: FullNameable {
var fullName: String
init(fullName: String) {
self.fullName = fullName
}
}

How do I use an existing property in a property wrapper when self hasn't been initialized? (SwiftUI)

I have a struct with two variables inside property wrappers. One of the variables is supposed to be computed from the other. When I try to do this, I get the following error:
Cannot use instance member 'name' within property initializer; property initializers run before 'self' is available.
I tried assigning a temporary value to these variables, and then re-assigning them within a custom init() function, but that doesn't seem to work ether. I made a simplified version of the code to see if I could isolate the issue.
import SwiftUI
struct Person {
#State var name: String = ""
#State var nameTag: NameTag = NameTag(words: "")
init(name: String) {
// not changing name and nameTag
self.name = name
nameTag = NameTag(words: "Hi, my name is \(name).")
}
}
class NameTag {
var words: String
init(words: String) {
self.words = words
}
}
var me = Person(name: "Myself")
// still set to initial values
me.name
me.nameTag.words
I noticed that when I changed nameTag to an #ObservedObject, rather than #State, it was able to be re-assigned correctly. Although I don't believe I can change name to #ObservedObject. Could anyone tell me what I'm doing wrong?
To use property wrappers in initializers, you use the variable names with preceding underscores.
And with State, you use init(initialValue:).
struct Person {
#State var name: String
#State var nameTag: NameTag
init(name: String) {
_name = .init(initialValue: name)
_nameTag = .init( initialValue: .init(words: name) )
}
}
Here's what a #State property really looks like, as your tear down levels of syntactic sugar:
name
_name.wrappedValue
$name.wrappedValue
_name.projectedValue.wrappedValue
You can't use the underscore-name outside of the initial type definition.

Initializing Realm Object class with multiple required initilizers

I am initializing Realm object and I am getting these errors when I try to initialize the class:
After I add the initializer for realm, the errors are still there. Is this a bug with xcode?
Looking at the sample code for swift-realm ios project here, it looks like I don't need to call the required realm. Maybe the sample code is outdated.
EDIT ---
Here's a paste of the code:
class AgencyR: Object {
#objc dynamic var agency_id: String = ""
#objc dynamic var agency_name: String = ""
#objc dynamic var agency_timezone: String = ""
#objc dynamic var agency_url: String = ""
#objc dynamic var agency_lang: String = ""
#objc dynamic var agency_phone: String = ""
#objc dynamic var agency_fare_url: String = ""
required init(realm:Realm, agency_id: String, agency_name: String, agency_timezone: String, agency_url: String, agency_lang: String, agency_phone: String, agency_fare_url: String) {
self.init()
self.agency_id = agency_id
self.agency_name = agency_name
self.agency_timezone = agency_timezone
self.agency_url = agency_url
self.agency_lang = agency_lang
self.agency_phone = agency_phone
self.agency_fare_url = agency_fare_url
}
override static func primaryKey() -> String? {
return self.agency_id
}
}
If you wanted to create a designated initializer for an Object subclass, you'd need to implement all required initializers of Object since the compiler will not be able to synthetise those for you anymore.
You can get around this issue by making your custom initializer a convenience initializer rather than a designated one, which will allow you to call a designated initializer of the class rather than having to call the superclass initializer. You can still mark the convenience initializer as required.
You also have an issue in your primaryKey function. Since the function is a type function, you don't have access to the instance from inside the function, so you cannot call self to access an instance property. However, there's no need to do that anyways, since you simply need to return the variable name as a String that you want to use as a primary key.
class A: Object {
#objc dynamic var a = 1
required convenience init(_ a:Int) {
self.init()
self.a = a
}
override static func primaryKey()->String?{
return "a"
}
}
It should be -> Object, instead of ->String? as agency_id is of type Object.Try this.

Struct variable initialize with setter

I'm new to Swift and I want to be able to write a property setter, which will also be used as a constructor when initializing:
struct Person {
private var name: String {
get {
return self.name;
}
set {
self.name = name;
}
}
}
var Murad = Person(name: "Murad");
When I run this code error return this error
argument passed to call that takes no arguments
The error occurs because the property is a computed property and it's private (can only be changed within the class), so for the compiler there is no (memberwise) initializer and only the default initializer Person() without parameter can be used.
You are in luck that you get this error message otherwise when you would run the code you will run into an infinite loop (which causes an overflow crash).
If you want a constant just declare the struct member as let
struct Person {
let name: String
}
let murad = Person(name: "Murad")
print(murad)

Why Are My Default Property Values Still Showing as Parameters in Init()?

I have a protocol that describes a marine water parameter that needs tested:
protocol Parameter {
var name: String { get }
var unit: Unit { get }
var value: Double { get }
}
I have a struct, Calcium, that conforms to Parameter:
struct Calcium: Parameter {
var name: String = "Calcium"
var unit: Unit = UnitDispersion.partsPerMillion
var value: Double
}
Since the name and unit parameters of Calcium have default values, why do I need to provide them in the init method? Shouldn't I only need to provide a value for value?
I am trying to understand protocol-oriented-programming and would really appreciate a little guidance here.
This has nothing whatever to do with protocols.
You do not have to provide an initializer for anything but the value. But you have not provided any initializer. Therefore the only initializer you have is the one provided automatically, and that initializer is the memberwise initializer which wants parameters for all your properties.
If you don't like that, write an initializer yourself:
struct Calcium: Parameter {
var name: String = "Calcium"
var unit: Unit = UnitDispersion.partsPerMillion
var value: Double
init(value:Double) {self.value = value}
}
Now it is legal to say:
let c = Calcium(value:2)