How to make an empty object in swift - swift

How do I initialize an empty object in swift? This is what I have but it wants the parameters too
var userInfo:User = User()
init(email: String, isVerified: String, profileImageURL: String, reputation: String, twitterHandle: String, userName: String) {
self._email = email
self._isVerified = isVerified
self._profileImageURL = profileImageURL
self._reputation = reputation
self._twitterHandle = twitterHandle
self._userName = userName
}

Create the class/struct with optional properties like this
struct Employee {//struct or class
var name: String?
var number: String?
var position: String?
}
Then you can create an object without any value, with some value
let emp = Employee()
let emp = Employee(name: nil, number: nil, position: nil)
let emp = Employee(name: "abc", number: nil, position: "xyz")
By creating a init method with default values parameter can be ignored while creating an object
struct Employee {
var name: String?
var number: String?
var position: String?
init(name: String? = nil, number: String? = nil, position: String? = nil) {
self.name = name
self.number = number
self.position = position
}
}
let emp = Employee()
let emp = Employee(name: "abc", number: "124", position: "xyz")
let emp = Employee(name: "abc", position: "xyz")
let emp = Employee(number: "124")
let emp = Employee(name: "abc", number: "124")

I assume you are creating empty User objects so that the information can be filled in later on. There are two problems I can see with this: one, object properties will all have to be variables and second, it's easy to make mistakes and pass the wrong information since the object does not always correspond to a real entity.
A better approach would be to define a set of parameters that are mandatory for a User object to be defined, and let every other parameters either be optional parameters, or give them default values. For example, if we choose username and email to be mandatory, and let profile image be optional, and isVerified to have a default value of false:
class User {
var userName: String
var email: String
var isVerified: Bool
var profileImageURL: String?
init(userName: String, email: String, isVerified: Bool = false) {
self.userName = userName
self.email = email
self.isVerified = isVerified
}
}

Related

How to append Bool value of a struct in Swift

So, I'm coding in Swift and I've made a struct called User. It has four categories of characteristics- name, email, number of followers, and activity status. I am able to append values of the variables of the structs I create without issue, so long as they are Strings or Ints, Dicts etc. It won't let me append the value of the Bool. I initially set it to 'true', but I'd like to append it to being 'false' after initializing it. I'm getting the error message: "Value of type 'Bool' has no member 'append'". I get that I'm not allowed to append it the same way as I can with say User.name.append("Tim"), but what I don't get is how I actually can append it. Google was unhelpful,searching in SO also yielded nothing of note, and Apple documentation on Structs shows them setting similar values in their explanation at the beginning using Strings and Bools and appending the Strings but not appending the Bools. I can't imagine it not being possible as things change all the time from true to false status, depending on the situation. If I remove the line below, it compiles fine.
userTwo.isAcctive.append(false) is where my error is, for clarity.
Any help would be appreciated!
struct User {
let name: String
let email: String?
var followers: Int
var isActive: Bool
init(name: String, email: String, followers: Int, isActive: Bool){
self.name = name
self.email = email
self.followers = followers
self.isActive = isActive
}
func logStatus(){
if isActive == true{
print("\(name) is working hard.")
} else {
print("\(name) has left the earth.")
}
}
}
var userOne = User(name: "Richard", email:("") , followers: 0, isActive: false)
var userTwo = User(name: "Elon", email:("elon#tesla.com") , followers: 2100, isActive: true)
print(userTwo.isActive)
userTwo.isActive.append(false)
userOne.logStatus()
userTwo.logStatus()
Appending is to add a new element to an array. I think you want to change isActive property. You can do this by:
var userTwo = User(name: "Elon", email:("elon#tesla.com") , followers: 2100, isActive: true)
userTwo.isActive = false
struct User {
var name :String
var email :String?
var followers :Int
var isActive :Bool
init(name: String, email: String?, followers: Int, isActive: Bool){
self.name = name
self.email = email!
self.followers = followers
self.isActive = isActive
}
func logStatus() {
if isActive == true {
print("\(name) is working hard")
}
else {
print("\(name) has left earth")
}
}
}
let userOne = User(name: "Richard", email:("richard#virgin"), followers: 0, isActive: false)
userOne.logStatus()
print("\nDiagnostic code (i.e., Challenge Hint):")
var musk = User(name: "Elon", email: "elon#tesla.com", followers: 2001, isActive: true)
musk.logStatus()
print("Contacting \(musk.name) on \(musk.email!) ...")
print("\(musk.name) has \(musk.followers) followers")
musk.isActive = false
musk.logStatus()

Simplify Swift data struct

Any suggestion on how to simplify this data struct? The data will be saved as a dictionary on the user's drive and when I read the data from the drive I have to convert them back to Member for easy accessing the properties.
I would like to have it typesafe.
struct Member {
var id: Int
var firstname: String
var lastname: String
var address: String?
var zipCode: Int?
var city: String?
enum Value: String {
case id = "id"
case firstname = "firstname"
case lastname = "lastname"
case address = "address"
case zipCode = "zipCode"
case city = "city"
}
var member: [String:Any] {
return [
Value.id.rawValue:Int(),
Value.firstname.rawValue:firstname,
Value.lastname.rawValue:lastname,
Value.address.rawValue:address ?? String(),
Value.zipCode.rawValue:zipCode ?? Int(),
Value.city.rawValue:city ?? String()
]
}
}
func memberToDic(member: Member) -> [String:Any] {
return [
Member.Value.firstname.rawValue:member.firstname,
Member.Value.lastname.rawValue:member.lastname,
Member.Value.address.rawValue:member.address ?? String(),
Member.Value.zipCode.rawValue:member.zipCode ?? Int(),
Member.Value.city.rawValue:member.city ?? String()
]
}
func dicToMember(dic: [String:Any]) -> Member {
return Member(
id: dic[Member.Value.id.rawValue] as! Int,
firstname: dic[Member.Value.firstname.rawValue] as! String,
lastname: dic[Member.Value.lastname.rawValue] as! String,
address: dic[Member.Value.address.rawValue] as? String,
zipCode: dic[Member.Value.zipCode.rawValue] as? Int,
city: dic[Member.Value.city.rawValue] as? String
)
}
Almost certainly, this is the correct implementation:
struct Member: Codable {
var id: Int
var firstName: String // "first name" is two words, so capitalize "name"
var lastName: String
var address: String // "No address" should be empty, not nil
var zipCode: String // ZIP codes are not integers
var city: String // "No city" should be empty, not nil
}
In order to save this as a plist, use PropertyListEncoder:
let data = try PropertyListEncoder().encode(member)
To read it, use PropertyListDecoder.
Codable automatically creates key mappings for your properties, so there's no need for Value.
You should strongly avoid creating or consuming [String: Any] dictionaries. These exist mostly due to Objective-C interfaces that could not generate strong types.
If address, zipCode, and city all should be set together, or not set together, then you should collect them into a single struct:
struct Address: Codable {
var streetAddress: String
var zipCode: String
var city: String
}
struct Member: Codable {
var id: Int
var firstName: String // "first name" is two words, so capitalize "name"
var lastName: String
var address: Address?
}
In this case, and Optional makes sense because "empty" is not the same thing as "missing."

How should I retrieve data from firebase and put it into a dictionary?

I have an organization document with a Members collection inside of it and then a members document inside of that. Inside the members document includes a Map of a user which is a member. The Key is the UserID and 3 values (firstName, lastName, username). I am trying to load in this data into my "Event" class that holds a membersInvited Property that is a dictionary. Inside the Event class is a method to get this data called getOrgMembers(). Even though I have that data in firebase I am getting a nil value for my dictionary. I also am using Dispatch but kind of new to it.
Below is code in the Event Class:
var membersInvited: [Member: Bool]?
func getOrgMembers(dispatch: DispatchGroup?) {
let membRef = BandzDatabase.collection("Organizations").document(currentUser.currentOrgID!).collection("Members").document("members")
membRef.getDocument { (snapshot, error) in
if let error = error {
print (error.localizedDescription)
} else {
if let data = snapshot?.data() {
for (key,value) in data {
if let membArray = value as? [String: Any] {
let username = membArray["username"] as? String
let firstName = membArray["firstName"] as? String
let lastName = membArray["lastName"] as? String
let userID = key
let member = Member(username: username ?? "", firstName: firstName ?? "", lastName: lastName ?? "", userID: userID)
self.membersInvited?.updateValue(true, forKey: member)
}
}
}
}
dispatch?.leave()
}
}
struct Member: Hashable {
var username: String
var firstName: String
var lastName: String
var userID: String
init (username: String, firstName: String, lastName: String, userID: String) {
self.username = username
self.firstName = firstName
self.lastName = lastName
self.userID = userID
}
}
Below is were I call this method from another class:
func getMembers() {
showActivityIndicatory(uiView: self.view)
self.dispatchGroup.enter()
eventMade?.getOrgMembers(dispatch: self.dispatchGroup)
self.dispatchGroup.notify(queue: .main) {
//self.tableView.reloadData()
stopActivityIndicator()
print("happens")
print(self.eventMade?.membersInvited)
}
}
After some research, I discovered that since I never initilized the dictionary, whenever I was calling to append key-value paires it would not even run since it was an optional. So I changed the decleration to this:
var membersInvited: [Member: Bool] = [:]

fatal error: use of unimplemented initializer 'init()' for class

I'm using Realm-Cocoa in a mixed project. There have been a few head-scratchers, but now I'm truly stuck. I have tried tried several things but nothing helps.
This class compiles with no complaints,but crashes at runtime:
fatal error: use of unimplemented initializer 'init()' for class 'MyApp.Model'
And here's the class:
import Foundation
import Realm
import SwiftyJSON
class Model: RLMObject {
dynamic var contactId: String
dynamic var userId: String
dynamic var contactType: String
dynamic var firstName: String
dynamic var lastName: String
dynamic var middleName: String
dynamic var jobTitle:String
dynamic var department: String
dynamic var location: String
dynamic var serviceName: String
dynamic var serviceType : String
dynamic var emails : String
dynamic var addresses :String
dynamic var profilePictureSHA1 : String
dynamic var extNum : String
dynamic var fqExtNum : String
dynamic var ipbxId : String
dynamic var phone : String
dynamic var fax : String
dynamic var dispWhenNoext : Bool
dynamic var dispInContDir : Bool
override class func primaryKey() -> String? {
return "contactId"
}
init(
contactId: String,
userId: String,
contactType: String,
firstName: String,
lastName: String,
middleName: String,
jobTitle: String,
department: String,
location: String,
serviceName: String,
serviceType: String,
emails: String,
addresses: String,
profilePictureSHA1: String,
dispWhenNoext: Bool,
dispInContDir: Bool,
extNum: String,
fqExtNum: String,
ipbxId: String,
phone: String,
fax: String)
{
self.contactId = contactId
self.userId = userId
self.contactType = contactType
self.firstName = firstName
self.lastName = lastName
self.middleName = middleName
self.jobTitle = jobTitle
self.department = department
self.location = location
self.serviceName = serviceName
self.serviceType = serviceType
self.emails = emails
self.addresses = addresses
self.profilePictureSHA1 = profilePictureSHA1
self.dispInContDir = dispInContDir
self.dispWhenNoext = dispWhenNoext
self.extNum = extNum
self.fqExtNum = fqExtNum
self.ipbxId = ipbxId
self.phone = phone
self.fax = fax
super.init()
}
override static func ignoredProperties() -> [String] {
return ["contactFlag", "dttmCreated", "nickName", "customField1", "customField2", "customField3", "serviceId", "parentServiceId", "branchId", "hideInAA", "vooEnableFlag", "devLockDown", "tenantId", "serviceEmailId", "siteCustomerId", "branchCode", "accessCode"]
}
}
See the Realm documentation on custom subclass initialisers and Swift introspection issues at: https://realm.io/docs/swift/latest/#adding-custom-initializers-to-object-subclasses
According to that doco, you should make it a convenience method, rather than a designated initialiser. Worth a try, anyhow. Something like:
convenience init(
contactId: String,
userId: String,
contactType: String,
firstName: String,
lastName: String,
middleName: String,
jobTitle: String,
department: String,
location: String,
serviceName: String,
serviceType: String,
emails: String,
addresses: String,
profilePictureSHA1: String,
dispWhenNoext: Bool,
dispInContDir: Bool,
extNum: String,
fqExtNum: String,
ipbxId: String,
phone: String,
fax: String)
{
self.init() // NB: 'self' not 'super'
self.contactId = contactId
self.userId = userId
self.contactType = contactType
self.firstName = firstName
self.lastName = lastName
self.middleName = middleName
self.jobTitle = jobTitle
self.department = department
self.location = location
self.serviceName = serviceName
self.serviceType = serviceType
self.emails = emails
self.addresses = addresses
self.profilePictureSHA1 = profilePictureSHA1
self.dispInContDir = dispInContDir
self.dispWhenNoext = dispWhenNoext
self.extNum = extNum
self.fqExtNum = fqExtNum
self.ipbxId = ipbxId
self.phone = phone
self.fax = fax
}

Swift: Reducing the length of Init methods

I would like to reduce the length of init method.
struct Person {
var id: Int
var firstName: String
var lastName: String
var vehicle: String
var location: String
var timeZone: String
init (id: Int, firstName: String, lastName: String, vehicle: String, location: String, timeZone: String ) {
self.firstName = firstName
self.lastName = lastName
self.vehicle = vehicle
self.location = location
self.timeZone = timeZone
}
}
Below is an instance of Person I am creating. I have to pass in the value of every single variable inline.
let person = Person(id: 22, firstName: "John", lastName: "Doe", vehicle: "Chevy", location: "Dallas", timeZone: "CST")
Question: How can I shrink the length of init? In Obj-C I used to create a data model class. Populate it's variables and then pass the entire class, reducing the length of the init method.
i.e.
Person *person = [Person new];
person.id = 22;
person.firstName = "John";
person.lastName = "Doe";
person.vehicle = "Chevy";
person.location = "Dallas";
person.timeZone = "CST"
Person *person = [Person initWithPerson:person];
What's an equivalent way in Swift to reduce the length of init without having to initialize every single variable inline? I know tuples is one way, is there any other best practice?
Just remove the initializer!
struct Person {
let id: Int
let firstName: String
let lastName: String
let vehicle: String
let location: String
let timeZone: String
}
Now you can use the memberwise initializer
Person(
id: 87112,
firstName: "Walter",
lastName: "White",
vehicle: "2004 Pontiac Aztek",
location: "Albuquerque",
timeZone: "UTC-07:00"
)
Structure types automatically receive a memberwise initializer if they do not define any of their own custom initialisers.
The Swift Programming Language
DO NOT use var
As you can see I replaced var with let.
Unless you need to change some properties of a Person after the value has been created, I suggest you to use let. Otherwise you are free to use var. This way the compiler will prevent unwanted changes.
DO NOT use Optionals
I don't know the business logic of your app, however if a Person must have all that 6 properties always populated, don't make them optionals. Otherwise every time you need to use a Person value the compiler will force you to check if that optional has a value.
DO NOT use Implicitly Unwrapped Optionals
Seriously. There are a few cases where they are useful and a model value is not one of them
Using a struct you actually don't need an initializer
struct Person {
var id : Int?
var firstName: String?
var lastName: String?
var vehicle: String?
var location: String?
var timeZone: String?
}
var person = Person()
person.id = 22
person.firstName = "John"
person.lastName = "Doe"
person.vehicle = "Chevy"
person.location = "Dallas"
person.timeZone = "CST"
You can do the same with non-optionals
struct Person {
var id = 0
var firstName = ""
var lastName = ""
var vehicle = ""
var location = ""
var timeZone = ""
}
Consider also the benefit of an initializer to declare (read-only) constants
struct Person {
let id : Int
let firstName : String
let lastName : String
let vehicle : String
let location : String
let timeZone : String
}
In this case you have to use the implicit memberwise initializer.
let person = Person(id: 22, firstName: "John", lastName: "Doe", vehicle: "Chevy", location: "Dallas", timeZone: "CST")
Like it was mentioned in the comments, an initializer will be created for you, and it'll look like this:
Person(id: Int?, firstName: String?, lastName: String?, vehicle: String?, location: String?, timeZone: String?)
However, you can also do this:
var person = Person()
person.id = 100
person.firstName = "Name"
...
Like you used to do in ObjC. Note that person was declared as var, because if it was declared as let, you wouldn't be able to mutate it.