Variable declaration with underscore - swift

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.

Related

Environmentobject keep track of arrays variables

I'm pretty new to xCode so this could have an obvious answer.
I've just learned about environment objects and created the following one:
import SwiftUI
class Data: ObservableObject {
#Published var types = [Type]()
#Published var customers = [Customer]()
#Published var templates = [SubscriptionTemplate]()
#Published var subscriptions = [Subscription]()
#Published var giftCodes = [Giftcode]()
}
As you can see the object contains an array of objects. One of these is a customer array. The customer object looks like this:
import SwiftUI
class Customer: Identifiable, Codable{
var id: Int
var firstname: String
var lastname: String
var address: String
var plz: Int
var place: String
var credit: Int
init(id: Int, firstname: String, lastname: String, address: String, plz: Int, place: String, credit: Int) {
self.id = id
self.firstname = firstname
self.lastname = lastname
self.address = address
self.plz = plz
self.place = place
self.credit = credit
}
}
extension Customer: Equatable {
static func == (lhs: Customer, rhs: Customer) -> Bool {
return lhs.id == rhs.id
}
}
In my project, I implemented an API call to update the customer. This works like a charm, but after updating, I also want to fetch the customer objects with the following method:
API().fetchCustomers { (customers) in
self.data.customers = customers
}
After updating an object this doesn't work. The environment object doesn't update, but after creating a new object or fetching the data initial, it works.
What is the difference between the update and the create / fetch?
Make Customer a value type (ie. struct):
struct Customer: Identifiable, Codable{
var id: Int
// ... other code

self.name = name in Swift . I don't understand why this codes are needed

class person {
var name : String
init(name: String) {
self.name = name
}
}
I am learning Swift class chapter
I don't understand why init(name:String) self.name = name code is needed
what the purpose of this code is.
I declared var name: String
and again init(name: String), why is self.name = name needed?
what's different between just var name and self.name = name?
Look into something called variable scope. In your code - there are two "name variables - a class (or instance) variable and a "parameter in your init.
The latter - init(name:) only is in use within your initialization function, meaning the instance has no name without the self.name = name once you've created the instance.
The former is available - to the instance - as long as your instance of the class person is.
To explain further, try this. Change your code to be:
class Person {
var myName : String
var myOtherName : String
init(name: String) {
self.myName = name
}
}
In your app or view controller, do this:
let myPerson = Person(name: "john")
print(myPerson.myName) // prints "jihoon"
print(myPerson.myOtherName) // prints nothing
print(myPerson.name) // generates a build error because name doesn't exist
One last note - in Swift class names are capitalized, so the best name is Person, not person.
Classes and structures must set all of their stored properties to an appropriate initial value by the time an instance of that class or structure is created. Stored properties cannot be left in an indeterminate state.
class person {
var name : String // undetrmined state
init(name: String) {
self.name = name
}
}
class person2 {
var name : String = "default value" // detrmined state
// Now these intializer are not optional. You can use these initializer or not.
init(name: String) {
self.name = name
}
init() {
}
}
// Aother example for optional stored property
class person3 {
var name : String? // detrmined state, because default value for optional is nil
// Now these intializer are not optional. You can use these initializer or not.
init(name: String) {
self.name = name
}
init() {
}
}
For more info read this one Apple Doc

Private property in data modeling and initializing

I'm beginner in Swift development.
I saw a video about data modeling in Swift. This code below:
private var _name: String!
var name: String {
return _name
}
Why we need to do that? I know it's good but can you explain to me about how it's better than normal ways like just define directly.
It seems like in your case you will have Invalid redeclaration of name - variable.
private var _name: String!
name = "xyz" {
return _name
}
or
private var _name: String = ""
name {return _name}

Init a computed variable

I'm going to create a new class, and in this class there's a computed variable; so I'm looking for a way to init this variable:
import UIKit
class Squadra: NSCoder, NSCoding
{
var nomeSquadra: String
var numeroCoriSquadra: Int
var coloreSquadra: String
var immagineSquadra: String
var sottotitoloSquadra: String
{
get
{
return "I migliori cori: \(nomeSquadra)"
}
}
init(nome: String, numero: Int, colore: String, immagine: String, sottotitolo: String)
{
nomeSquadra = nome
coloreSquadra = colore
numeroCoriSquadra = numero
immagineSquadra = immagine
sottotitoloSquadra = sottotitolo
}
}
obviously with this line of code Xcode gives my a compile error (because the var is a get only property).
I think that i have to use a set to make the var writable, but I don't know how to operate because I don't know exactly how get and set work.
Either remove sottotitoloSquadra = sottotitolo or assign to a different variable. Even if the assignment worked, you never actually use the value that comes in as sottotitolo for anything.
I can't see useful behavior while you use independent property nomeSquadra and trying to have setter for sottotitoloSquadra at the same time. Maybe better to use hidden support property for computed variable in your case?
private var _sottotitoloSquadra: String
var sottotitoloSquadra: String
{
get
{
return "I migliori cori: \(_sottotitoloSquadra)"
}
set
{
_sottotitoloSquadra = newValue
}
}
init(nome: String, numero: Int, colore: String, immagine: String, sottotitolo: String)
{
//...
_sottotitoloSquadra = sottotitolo
}
If I understand you class correctly, you want to use the variable's default string when the init() did not provide a value (I'm just guessing though).
So if the team doesn't have a specific subTitle, you would make one up from the team's name.
I also understand that you don't want that property to be modifiable after the object is instantiated.
If that is the case, (I assume you would get an empty string for sottotitolo), you can define a private variable to hold the provided title and expose it using a computed variable. The default value (made up title) can be returned by that computed variable if a title was not supplied on the init().
class Squadra
{
var nomeSquadra: String
var numeroCoriSquadra: Int
var coloreSquadra: String
var immagineSquadra: String
private var _sottotitoloSquadra = ""
var sottotitoloSquadra: String
{
return _sottotitoloSquadra == ""
? "I migliori cori: \(nomeSquadra)"
: _sottotitoloSquadra
}
init(nome: String, numero: Int, colore: String, immagine: String, sottotitolo: String)
{
nomeSquadra = nome
coloreSquadra = colore
numeroCoriSquadra = numero
immagineSquadra = immagine
_sottotitoloSquadra = sottotitolo
}
}
Only your class, including its init() function, can modify the private variable holding the supplied sottotitolo. Outside of that source file, the private variable is not accessible at all.

How do I create a class that requires an instance variable to be set?

public class User : NSObject {
var id: Int //will throw an error during build
var name: String?
override init(){
}
convenience init(id: Int, name: String?){
self.id = id
self.name = name
}
}
I want to create a user class. The id should non-optional. However, my above code does not work unless I change the line to:
var id: Int = 0
I don't want to do this. Is there a better way?
Delete the word convenience! Convenience is exactly the opposite of what you want. You want this to be a designated initializer. Like this:
public class User : NSObject {
var id: Int
var name: String?
init(id: Int, name: String?){
self.id = id
self.name = name
super.init()
}
}
This forces the creator of a User to supply an id, which is exactly what you want.
public class User {
let id: Int
var name: String?
init(id: Int, name: String? = nil) {
self.id = id
self.name = name
}
}
let user = User(id: 3) // works without errors
As you can see, I changed some things. You probably don't really need to subclass NSObject, and I don't think you'll want to change a user's id after initialisation, so it makes more sense to make it a let constant.