I've looked across Google and have found no answer to the below..
I'm looking to prepend a single String character to a list of numbers: A12345
In the example below I'm creating the class and when declaring an instance, setting the employeeNumber to 12345. Later on, when the property is called, I'd like it to return employeeNumber prepend with the letter p.
class Employee {
var surname: String
let forename: String
let employeeNumber: Int {
set {
"p\(employeeNumber)"
}
}
}
let employeeOne = Employee(surname: "Jones", forename: "Tom", employeeNumber: 12345)
employeeOne.employeeNumber // returns A12345
I appreciate that this code might be WELL off what I should be using (i.e using a setter?).
What you are looking for is a function (or a computed property) that returns a String value made of the employee number prefixed by a letter:
struct Employee {
var surname: String
var forename: String
var employeeNumber: Int
var employeeNumberAsString: String {
"A\(employeeNumber)"
}
}
let employee = Employee(surname: "Jones", forename: "Tom", employeeNumber: 12345)
print(employee.employeeNumberAsString)
// prints "A12345"
Your employee number is an Int, you can't set it with a String, use a property that stores the number and a function to retrieve the formatted number.
Related
I am using Mirror to access the children of my struct like this:
struct TestType {
var firstName: String
var lastName: String
var value: String {
return firstName + lastName
}
}
use case:
let person: TestType = TestType(firstName: "Tim", lastName: "Cook")
for property in Mirror(reflecting: person).children {
print("label: \(property.label!)", "value: \(property.value)")
}
results:
label: firstName value: Tim
label: lastName value: Cook
Now my goal is do the same thing for the person constant as well, with that said, I want be able to access the label of person which is person and the value of it, the result should look like this:
label: person value: Tim Cook
How can i do this in Swift?
Honestly I have no idea why need to use Mirror here) would be great if you would describe it in as a comment below this answer. I would appreciate it)
but the reason why you can't what you need is because of Mirror can't see computed properties, as far as I know. Any way you can customise your init method to reach what you need. But remember that using Mirror is too expensive, for example: if it in inherited object it will parse every single thing in parent classes which could be accessible for Mirror
struct TestType {
let firstName: String
let lastName: String
let person: String
init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
person = [firstName, lastName].joined(separator: " ")
}
}
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.
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.
Having array of employee object, called employees and now I want to create another array called filteremployees which is having only id and date of birth value.
Using
let filteremployees = employee.map({ $0.id})
I can get array which contains only id value but i want to have id as well dateOfBirth
class Employee {
var id: Int
var firstName: String
var lastName: String
var dateOfBirth: NSDate?
init(id: Int, firstName: String, lastName: String) {
self.id = id
self.firstName = firstName
self.lastName = lastName
}
}
Try this:
let employees : [Employee] = ...
let list: [(Int, NSDate?)] = employees.map { ($0.id, $0.dateOfBirth) }
You must explicitly declare the type of list otherwise you get this error from the compiler
Type of expression is ambiguous without more context.
Tested with Xcode 7 Playground and Swift 2.0.
Hope this helps.
You could try using the same map method and returning a tuple of your expected values:
let filter employees: [(Int, NSDate?)] = employee.map({ ($0.id, $0.dateOfBirth) })
Alternatively, and I think this is a better solution, create a new value type and create that with only your required values
struct FilteredEmployee {
let id: String
let dateOfBirth: NSDate?
init(employee: Employee) {
id = employee.id
dateOfBirth = employee.dateOfBirth
}
}
And then you can map the initialiser over the array
let filteremployees = employee.map { FilteredEmployee($0) }
I have a Swift Class called Person and it has three values: First name, last name and birthday (String, String and NSDate). Now I have function which I want to use to print something based on an attribute - for example when the attribute is myPerson.name it should print the following: This person's name is .... My question is now is it possible to make a function which takes a parameter of the class Person as parameter? For example: func myFunction(parameter:Person.parameter) {} (I know there's no Person.parameter but it's just an example).
I know there are easier solutions but it would be helpful for me for another project. Thank in advance.
You can create a new property name and override it's getter to return 'This person's name is ... ' text,
class Person{
let firstName: String
let lastName: String
init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
}
var name: String {
get {
return "This person's name is \(firstName) \(lastName)"
}
}
}
let person = Person(firstName: "Sandeep", lastName: "Koirala")
person.name
Regarding the function, you can create a new function which takes Person as object and then perform some calculation on its property like this,
func printPersonsName(person: Person) {
print(person.name)
}