Initializers in class swift - swift

What is the difference in initializing a variable:
class Person {
var name = String()
}
instead of:
class Person {
var name : String
init(name: String) {
self.name = name
}
}
thanks

First snippet
You can call
let person = Person()
Second snippet:
You must call
let person = Person(name:"")
to get an instance with an empty name property
PS: "" is easier to write than String()

Related

Why Instance member 'getPerson' cannot be used on type 'GetPerson'

I write code in a Cocoa framework and call the function in it from main project. But it fails always returning a message. I fix this in two ways.
First, in main project viewController:
import getPerson
override func viewDidLoad() {
super.viewDidLoad()
var person = GetPersons.getPerson(name: "Jack")
}
Returns:
Instance member 'getPerson' cannot be used on type 'GetPerson'; did you mean to use a value of this type instead
Second:
import getPerson
override func viewDidLoad() {
super.viewDidLoad()
let vc = GetPersons.self
var person = vc.getPerson(name: "Jack")
}
Returns:
Instance member 'getPerson' cannot be used on type 'GetPersons'
What's happening with this? How do I fix it?
In test framework :
import Fundation
public class GetPersons {
public struct Person {
public var name : String = ""
public var age : Int = 0
}
public func getPerson(name : String) -> Person {
var person = Person()
return person
}
}
In your first example, it's telling you that you defined getPerson(name: String) as an instance method. (Presumably because it operates on instance properties.)
You are calling it here as if it were defined as:
static func getPerson(name: String) { ...
The second is saying much the same thing, without guessing what you want to do.
If I understand what you want to do, I think it goes something like this:
class GetPersons {
struct Person {
public var name : String = ""
public var age : Int = 0
}
func getPerson(name : String) -> Person {
var person = Person()
return person
}
}
Then, in your view controller define a property for the instance of GetPersons:
let gp = GetPersons()
then in viewDidLoad:
let person = gp.getPerson(name: "Jack")
Also, is GetPersons in an actual framework, or is it simply a class defined (as it should be) in a separate file?

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

Swift inheritance issue. How to get appropriate class object

I have two classes (to simplify I drop other filed the object is more complicated then the Person):
class Person
{
var name: String = "Default name"
init(object: PersonEntity)
{
name = object.daysMask
}
}
class Employer: Person
{
}
I have function that configure for me a person
func getConiguratedPerson(name: String) -> Person
{
let person = Person()
person.name = name
}
In case if I want to get Person I simple do this:
let person = getConiguratedPerson("Alex")
but what if I need Employer instead and I want to use this function as well
let employer = getConiguratedPerson("Alex") // returns Person as expected but need to have employer instead.
In Objective-C we can simple do this:
Employer *employer = Employer([self getConiguratedPerson:"Alex"]) if I remember.
The mistake is the getConfiguredPerson function. You want an initializer. Initializers return your own class, which is exactly what you want.
class Person {
var name: String = "Default name"
init(name: String) {
self.name = name
}
init(object: PersonEntity) {
self.init(object.daysMask)
}
}
class Employer: Person {}
Now to create a person, you just use Person(name: "Alex") and to get an employer you use Employer(name: "Alex").
Note that this is true in ObjC as well. You shouldn't have getConfiguredPerson there either. You'd should have [Person initWithName:].
You can't use upcasting here, because configured person is not of Employee type, but of Person type. To achieve the desired result I would suggest something like this:
class Person {
var name = "name"
required init() { }
}
class Employee: Person { }
func getPerson<T: Person>(name: String) -> T {
let person = T()
person.name = name
return person
}
let employee: Employee = getPerson("Alex")
or this if type of object returning by factory method depends on input:
func getPerson(name: String) -> Person {
if name != "Alex" {
return Person()
}
return Employee()
}
let employee = getPerson("Alex") as! Employee

How do I get value from superclass attribute?

Suppose I have SuperClass and I want to get its attribute value to subclass
class Person {
var name = String()
init(name : String){
self.name = name
}
}
var JonSnow = Person(name : "Jon Snow")
class Ranger : Person {
func getRangerName()->String {
return "Ranger name is \(super.name)"
}
// I want to get name value from super class
}
How do I get name value directly from super class Without reinit the value in subclass ?
You can simply access it self.x
So using your code:
class Person {
var name : String = "Jon Snow"
}
class Ranger : Person {
func printName() {
print(self.name)
}
}
Edit
Here is a full working project with that example implemented: download project

Access properties via subscripting in Swift

I have a custom class in Swift and I'd like to use subscripting to access its properties, is this possible?
What I want is something like this:
class User {
var name: String
var title: String
subscript(key: String) -> String {
// Something here
return // Return the property that matches the key…
}
init(name: String, title: String) {
self.name = name
self.title = title
}
}
myUser = User(name: "Bob", title: "Superboss")
myUser["name"] // "Bob"
Update: The reason why I'm looking for this is that I'm using GRMustache to render from HTML templates. I'd like to be able to just pass my model object to the GRMustache renderer…
GRMustache fetches values with the keyed subscripting objectForKeyedSubscript: method and the Key-Value Coding valueForKey: method. Any compliant object can provide values to templates.
https://github.com/groue/GRMustache/blob/master/Guides/view_model.md#viewmodel-objects
This is a bit of a hack using reflection. Something along the lines of the following could be used.
protocol PropertyReflectable { }
extension PropertyReflectable {
subscript(key: String) -> Any? {
let m = Mirror(reflecting: self)
for child in m.children {
if child.label == key { return child.value }
}
return nil
}
}
struct Person {
let name: String
let age: Int
}
extension Person : PropertyReflectable {}
Then create a Person and access it's keyed properties.
let p = Person(name: "John Doe", age: 18)
p["name"] // gives "John Doe"
p["age"] // gives 18
You could modify the subscript to always return an interpolated string of the property value.
Adding some syntax sugar to Benzi's answer:
protocol PropertyReflectable { }
extension PropertyReflectable {
subscript(key: String) -> Any? {
let m = Mirror(reflecting: self)
return m.children.first { $0.label == key }?.value
}
}
struct Person: PropertyReflectable {
let name: String
let age: Int
}
Then create a Person and access it's keyed properties.
let p = Person(name: "John Doe", age: 18)
p["name"] // gives "John Doe"
p["age"] // gives 18
Using valueForKey should enable you to access properties using their names. Be sure that you're working with a object that inherit NSObject
class people: NSObject {
var age: NSString = "44"
var height: NSString = "153"
}
let person:people = people()
let stringVariable = "age"
person.valueForKey("age")
// Print "44"
person.valueForKey("\(stringVariable)")
// Print "44"
(GRMustache author here)
Until a swift-oriented Mustache library is out, I suggest having your classes inherit from NSObject (so that they have the valueForKey: method). GRMustache will then fetch values with this method.
In case this would still not work (blank values in the rendering), you may try to disable GRMustache security features (see https://github.com/groue/GRMustache/blob/master/Guides/security.md#disabling-safe-key-access)
Should you experience any other trouble, please open an issue right into the repository: https://github.com/groue/GRMustache/issues
EDIT February 2, 2015: GRMustache.swift is out: http://github.com/groue/GRMustache.swift
Shim's answer above doesn't work anymore in Swift 4. There are two things you should be aware of.
First of all, if you want to use value(forKey:) function, your class must inherit NSObject.
Secondly, since Objective-C doesn't know anything about value type, you have to put the #objc keyword in front of your value type properties and Swift will do the heavy-lifting for you.
Here is the example:
import Foundation
class Person: NSObject {
#objc var name: String = "John Dow"
#objc var age: Int = 25
#objc var height: Int = 180
subscript(key: String) -> Any? {
return self.value(forKey: key)
}
}
let person: Person = Person()
person["name"] // "John Dow"
person["age"] // 25
person["height"] // 180
I suppose you could do:
class User {
let properties = Dictionary<String,String>()
subscript(key: String) -> String? {
return properties[key]
}
init(name: String, title: String) {
properties["name"] = name
properties["title"] = title
}
}
Without knowing your use case I would strongly advise against doing this.
Another approach:
class User {
var name : String
var title : String
subscript(key: String) -> String? {
switch key {
case "name" : return name
case "title" : return title
default : return nil
}
}
init(name: String, title: String) {
self.name = name
self.title = title
}
}
It might be worth noting that Swift doesn't appear to currently support reflection by names. The reflect function returns a Mirror whose subscript is Int based, not String based.