I am learning swift on my own but I cannot manage to make this code run, I am trying to create a class "Inhabitant" inheriting from Person class with a new "Country" property, have 2 initializers:
- one that takes firstname and lastname and sets the country to an empty String
- one that takes firstname, lastname and country
and create a computed property description of String type that return a the firstname, lastname and country separated by a space
class Person {
var firstname: String
var lastname: String
var fullname: String {
return firstname + " " + lastname
}
init(firstname: String, lastname: String) {
self.firstname = firstname
self.lastname = lastname
}
}
class Inhabitant: Person {
var country: String? = nil
var description: String {
return firstname + " " + lastname + " " + country ?? ""
}
override init(firstname: String, lastname: String) {
super.init(firstname: <#T##String#>, lastname: <#T##String#>)
self.country = ""
}
init(firstname: String, lastname: String, Country: String) {
super.init(firstname: <#T##String#>, lastname: <#T##String#>)
}
}
func tst() {
let perso = Inhabitant(firstname: "toto", lastname: "bobo")
print(perso)
}
The code won't run:
Editor placeholder in source file
I would do something like this:
class Person {
var firstname: String
var lastname: String
var fullname: String {
return firstname + " " + lastname
}
init(firstname: String, lastname: String) {
self.firstname = firstname
self.lastname = lastname
}
}
class Inhabitant: Person {
var country: String? = nil
var description: String {
//1
return "\(firstname) \(lastname) \(country ?? "")"
}
override init(firstname: String, lastname: String) {
//2
super.init(firstname: firstname, lastname: lastname)
self.country = ""
}
init(firstname: String, lastname: String, country: String) {
super.init(firstname: firstname, lastname: lastname)
self.country = country
}
}
func tst() {
let perso = Inhabitant(firstname: "toto", lastname: "bobo")
let perso2 = Inhabitant(firstname: "toto", lastname: "bobo", country: "Belgium")
print(perso.fullname)
print(perso2.description)
}
tst()
Explanations:
String interpolation in swift are done with this syntax, cf swift programming language
When you override the initialiser, what you want is to pass the arguments you receive to your super initialiser.
Related
Im making a userProfile class in swift which includes the following code:
class userProfile {
var firstname: String!
var username: String!
var lastname: String!
var uid: String!
init(uid: String, dictionary: Dictionary<String, AnyObject>) {
self.uid = uid
if let username = dictionary["username"]as? String {
self.username = username
}
if let firstname = dictionary["firstname"]as? String {
self.firstname = firstname
}
if let lastname = dictionary["lastname"]as? String {
self.lastname = lastname
}
}
}
and i am trying to access the the attributes in another class with the following code:
var user: userProfile? {
didSet {
let fullName = userProfile?.firstname
firstname.text = fullName
}
}
But when i do this i get the following error and i don't know why:
Type 'userProfile?' has no member 'firstname'
how di i fix this?
Here is a fix (you tried to access class, but should be instance) :
var user: userProfile? {
didSet {
let fullName = user?.firstname // << here !!
firstname.text = fullName // I can't say if this valid
}
}
To avoid such ambiguity you should follow a rule to name classes in UpperCase, ie. in you case UserProfile.
I have some trouble to init() a class in another class.
I've been looking if I can find a solution in here but I wasn't able to.
If I write super.init() there comes another error because the function isn't existing.
I don't know where I have to initialize it.
I'd prefer to init the Address class in the open init from the Contact class but if I do so I can't access the Address class.
I think that it isn't a big mistake but I'm not able to find it.
open class Contact: Identifiable {
public var id: Int64?
var FirstName: String
var Name: String
var Phone: String
var Mail: String
var Birth: String
var News: Bool
open class Adress: Contact {
var Street: String
var Number: String
var PostalCode: String
var City: String
var Country: String // Error:'super.init' isn't called on all paths before returning from initializer
//If I add the Super.Init() there is an error because Super.Init() isn't existing and I don't know where to create it.
init(Street: String, Number: String, PostalCode: String, City: String, Country: String) {
self.Street=Street
self.Number=Number
self.PostalCode=PostalCode
self.City=City
self.Country=Country
}
}
public init(id: Int64, Firstname: String, Name: String, Phone: String, Mail: String, Birth: String, News: Bool) {
self.id = id
self.FirstName = Name
self.Name = Name
self.Phone = Phone
self.Mail = Mail
self.Birth = Birth
self.News = false
}
}
Technically you could do it this way:
class Contact: Identifiable {
public var id: Int64
var name: String
class Address: Contact {
var street: String
init(street: String, contact: Contact) {
self.street = street
super.init(id: contact.id, name: contact.name)
}
}
public init(id: Int64, name: String) {
self.id = id
self.name = name
}
}
let contact = Contact(id: 1, name: "name")
let address = Contact.Address(street: "street", contact: contact)
But maybe you want to model it in a way that a Contact has an Address:
class Contact: Identifiable {
public var id: Int64
var name: String
var address: Address
public init(id: Int64, name: String, address: Address) {
self.id = id
self.name = name
self.address = address
}
}
class Address: Identifiable {
var id: Int64
var street: String
public init(id: Int64, street: String) {
self.id = id
self.street = street
}
}
let address = Address(id: 1, street: "street")
let contact = Contact(id: 2, name: "name", address: address)
I have a model which uses init with JSON, so that i can create objects directly from an API response.
However in this instance I want to init the model and manually enter its properties, hence it wont be JSON.
How can i have another init method that allows me to not use the standard JSON method and instead manually enter my params?
The model looks like this...
class Conversation: NSObject {
var id: String
var index: String
var image: String
var firstname: String
var lastname: String
var withuserid: String
var badgeCount: String
init?(_ json: JSON) {
guard let id = json["id"].string,
let index = json["index"].string,
let image = json["image"].string,
let firstname = json["firstname"].string,
let lastname = json["lastname"].string,
let withuserid = json["withuserid"].string,
let badgeCount = json["badgeCount"].string
else { return nil }
self.id = id
self.index = index
self.image = image
self.firstname = firstname
self.lastname = lastname
self.withuserid = withuserid
self.badgeCount = badgeCount
}
}
Just add another init since you can several ones for a struct and class Then just call the desired one:
class Conversation: NSObject {
var id: String
var index: String
var image: String
var firstname: String
var lastname: String
var withuserid: String
var badgeCount: String
init?(_ json: JSON) {
guard let id = json["id"].string,
let index = json["index"].string,
let image = json["image"].string,
let firstname = json["firstname"].string,
let lastname = json["lastname"].string,
let withuserid = json["withuserid"].string,
let badgeCount = json["badgeCount"].string
else { return nil }
self.id = id
self.index = index
self.image = image
self.firstname = firstname
self.lastname = lastname
self.withuserid = withuserid
self.badgeCount = badgeCount
}
init(id: String, index: String, image: String, firstName: String, lastName: String, withUserId: String, badgeCount: String) {
self.id = id
self.index = index
self.image = image
self.firstName = firstName
self.lastName = lastName
self.withUserId = withUserId
self.badgeCount = badgeCount
}
}
A single class or struct can have several designated initializers in Swift.
Then you can call the non-JSON init method like this:
let conv = Conversation(id: "asbe", index: "1", "image: "img", firstName: "John", lastName: "Smith", withUserId: "21", badgeCount: "5"
class Conversation {
var id: String
var index: String
var image: String
var firstName: String
var lastName: String
var withUserId: String
var badgeCount: String
init(id: String, index: String, image: String, firstName: String, lastName: String, withUserId: String, badgeCount: String){
self.id = id
self.index = index
self.image = image
self.firstName = firstName
self.lastName = lastName
self.withUserId = withUserId
self.badgeCount = badgeCount
}
init?(_ json: JSON) {
guard let id = json["id"].string,
let index = json["index"].string,
let image = json["image"].string,
let firstname = json["firstname"].string,
let lastname = json["lastname"].string,
let withuserid = json["withuserid"].string,
let badgeCount = json["badgeCount"].string
else { return nil }
self.id = id
self.index = index
self.image = image
self.firstname = firstname
self.lastname = lastname
self.withuserid = withuserid
self.badgeCount = badgeCount
}
}
Some general advice: I don't see any reason for the class to inherit from NSObject. Swift classes don't need to inherit from any class, so unless you explicitly need a method from another class, don't make your custom classes inherit from others for no reason.
Please make sure you conform to the Swift naming convention, which is lower-camelCase for variable names. I would also rethink the types of some of the variables, without more context, it seems to me, some of them should be of type Int instead of String.
Iam new in Swift and i want to convert my struct into parameter to post it with Alamofire 4.
Please excuse my bad english.
My struct is in another Class:
import Foundation
class structUser: NSObject{
var myStructUser = [person]()
struct person {
var firstName : String
var lastName : String
var age: Int
init ( firstName : String, lastName : String, age : Int) {
self.firstName = firstName
self.lastName = lastName
self.age = age
}
}
override init(){
myStructUser.append(person(firstName: "John", lastName: "Doe", age: 11))
myStructUser.append(person(firstName: "Richard", lastName: "Brauer", age : 22))
myStructUser.append(person(firstName: "Merrideth", lastName: "Lind", age : 55))
}
}
now in the Main Class I want to post the Alamofire, but how can I convert only the first name and the age from the struct?
import UIKit
class ViewController: UIViewController {
let classStructUser = structUser()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
print(classStructUser.myStructUser)
}
func postJson(){
//need format [String : Any]
for item in classStructUser.myStructUser{
// var name = classStructUser.myStructUser.name
// var age = classStructUser.myStructUser.age
}
print(classStructUser.myStructUser)
/*here i need the Json in format:
{
"name":"John",
"age":11
}
{
"name":"Richard",
"age":22
}
{
"name":"Merrideth",
"age":55
}
an so on array.count
*/
}
}
another Question:
How can I access a variable in the struct(structUser) from VieControllerClass
thx for your help! And please explain the full solution, because i want to understand how ist works.
Thx!
class structUser: NSObject{
var myStructUser = [person]()
struct person {
var firstName : String
var lastName : String
var age: Int
init ( firstName : String, lastName : String, age : Int) {
self.firstName = firstName
self.lastName = lastName
self.age = age
}
static func jsonArray(array : [person]) -> String
{
return "[" + array.map {$0.jsonRepresentation}.joined(separator: ",") + "]"
}
var jsonRepresentation : String {
return "{\"name\":\"\(firstName)\",\"age\":\"\(age)\"}"
}
}
func jsonRepresentation() -> String {
return person.jsonArray(array: myStructUser)
}
override init(){
myStructUser.append(person(firstName: "John", lastName: "Doe", age: 11))
myStructUser.append(person(firstName: "Richard", lastName: "Brauer", age : 22))
myStructUser.append(person(firstName: "Merrideth", lastName: "Lind", age : 55))
}
}
And use it like this.
let jsonString = classStructUser.myStructUser.jsonRepresentation()
public class User {
var id: Int
var fb_id: String?
var first_name: String?
var last_name: String?
var age: Int?
var distance: Int?
var login_at_pretty: String?
var login_at: Int?
var profile: Profile?
init(id: Int, fb_id: String?, first_name: String?, last_name: String?, age: Int?, distance: Int?, login_at_pretty: String?, login_at: Int?, profile: Profile?){
self.id = id
if let fb_id = fb_id {
self.fb_id = fb_id
}
if let first_name = first_name {
self.first_name = first_name
}
if let last_name = last_name {
self.last_name = last_name
}
if let age = age {
self.age = age
}
if let distance = distance {
self.distance = distance
}
if let login_at_pretty = login_at_pretty {
self.login_at_pretty = login_at_pretty
}
if let login_at = login_at {
self.login_at = login_at
}
if let profile = profile {
self.profile = profile
}
}
}
Is this the quickest way to do it? I feel like I'm over typing.
For your class, you're doing a lot of if-let statements that don't provide anything useful. ie:
if let fb_id = fb_id {
self.fb_id = fb_id
}
fb_id and self.fb_id are optionals, so the binding isn't necessary. Just do:
self.fb_id = fb_id
On that note however, if you're not planning on subclassing, using a struct would provide a memberwise initializer automagically:
public struct User {
var id: Int
var fb_id: String?
var first_name: String?
var last_name: String?
var age: Int?
var distance: Int?
var login_at_pretty: String?
var login_at: Int?
var profile: Profile?
}
Check out Memberwise Initializers for Structure Types in the swift docs