Could you please tell me why that code (class) is working in playground?
If I understand properly there should be init or something that can be used by "blank initializer"?
class Shape{
var numberOfSides = 0
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
var shapeA = Shape()
shapeA.simpleDescription()
shapeA.numberOfSides = 7
var shapeDescription = shapeA.simpleDescription()
shapeA.simpleDescription()
Thank you for your help
If all the stored properties are given default values, as here, the class does not need to have an explicit initializer.
In Swift an init override is only required in certain cases.
For instance, if you hadn't put a default value on that numberOfSides var then you would have to have an init to provide the default value.
Or you would have had to make it optional which gives it a nil default value.
This is all explained in the iBook by apple.
Related
Looking through a Swift MIDI library, I found a variable initialised like so:
var client = MIDIClientRef()
I only thought this was weird after realising that MIDIClientRef isn't a function, it's a typealias for a UInt32, so wondered why the constructor pattern is used.
So a few simple questions:
Is it common to initialise a variable like this: var myVar = Int()?
Which types initialise with a default zero value when initialised with a constructor like this?
How does it initialise with a zero value if no argument is passed in?
Looking at the public init() function in Swift.Math.Integers the comments state that it "Creates a new value equal to zero." But I couldn't find what actually creates this default value in the following code.
UInt32 conforms to the BinaryInteger protocol and that requires an init() method which “Creates a new value equal to zero.”
There is also a default implementation which can be found in Integers.swift:
extension BinaryInteger {
/// Creates a new value equal to zero.
#_transparent
public init() {
self = 0
}
// ...
}
Other types have explicit no-argument init methods, like all floating point types:
#_transparent
public init() {
let zero: Int64 = 0
self._value = Builtin.sitofp_Int64_FPIEEE${bits}(zero._value)
}
Examples:
let d = Double()
let f = Float()
let c = CGFloat()
Finally, all types which are imported from C have a default initializer in Swift that initializes all of the struct's fields to zero, as mentioned in the Xcode 6 release notes. Example (from Do I need to memset a C struct in Swift?):
let hints = addrinfo()
It is an initializer on BinaryInteger protocol. It is declared as
extension BinaryInteger {
/// Creates a new value equal to zero.
#_transparent
public init() {
self = 0
}
// ...
}
You can check its implementation at Integers
I am writing my project and wondered.
When I read literature or watch videos, I see that this is bad practice. Why? Is this bad for the system?
What is the difference between this
class SomeClass {
var someView = SomeView()
var someViewModel = SomeViewModel()
// ...
}
and this
class SomeClass {
var someView: SomeView!
var someViewModel: SomeViewModel?
// ...
}
How to get used to it better?
You have to initialize all instance properties somehow. And you have to do it right up front, either in the declaration line or in your init method.
But what if you don't actually have the initial value until later, like in viewDidLoad? Then it is silly to supply a real heavyweight value only to replace it later:
var v = MyView()
override func viewDidLoad() {
self.v = // get _real_ MyView and assign it in place of that
}
Instead, we use an Optional to mark the fact that we have no value yet; until we obtain and assign one, it will be nil:
var v : MyView? // means it is initially `nil`
override func viewDidLoad() {
self.v = // get _real_ MyView and assign it to our property
}
There's nothing wrong with the first way (which is called a "default property value", by the way), and in fact, often times it's preferable. But of course, the devil is in the details:
How would the initialization of a SomeViewModel work? Without acess the initializer parameters of SomeClass, you're stuck with only being able to construct an instance from a parameter-less init, like SomeViewModel(). What exactly could that do? Suppose it was a person view model, and you had PersonViewModel(). What person? Whats their name? What will this default value do at all?
It's not a great pattern if it requires overwriting the default value with some other value in the initializer
It initializes the value up-front, where sometimes a lazy or computed value might be more appropriate.
class TestClass {
var testString: String = {
print("about to initialize the property")
return "TestString"
}()
}
let testClass = TestClass()
print("before first call")
print(testClass.testString)
print(testClass.testString)
In the above program, I am getting the return value from a property. Is it possible because I have heard we been doing it for methods.
func method() -> String {
return "a string"
}
This is what I know. Can anyone elaborate my doubt?
Yes it's possible and recommended since Swift 3. If you need to get just one value without passing other values to compute it, this is the recommended approach.
For example, in Swift 2 you had UIColor.redColor() returning a red color, but since Swift 3 you need to use UIColor.redColor
Yet it is possible. These are called Computed Properties, and are thoroughly explained in the Swift Documentation
For a project I am currently working on, it would be very useful to get the KVC-String from a KeyPath instance my method is receiving. Short example:
struct Person {
var name: String
}
let propertyCache = ["name": "something"]
func method<T>(_ keypath: KeyPath<Person, T>) -> T? {
let kvcName = keypath.kvc
return propertyCache[kvcName]
}
This might seem not very useful, but in my project it is :) I found a property on KeyPath called _kvcKeyPathString which is also public, but it returns nil every time I tried.
Or is their maybe a possibility to use reflection there? Thanks in advance for ideas/solutions!
I don't know of a pure Swift way to get the name of the property as a string yet.
But, if you add the #objc attribute to the property then _kvcKeyPathString will actually have a value instead of always being nil. Also, since Swift structs can't be represented in Objective-C, this method only works for classes.
A minimal working example usage:
class SomeClass {
#objc var someProperty = 5
}
let keyPath = \SomeClass.someProperty
print(keyPath._kvcKeyPathString)
There has been same titles of this question but different situations.
In this case this is very simple but I can't find a same problem online.
So here's the code
class ViewController: UIViewController {
#IBOutlet weak var fldTotalUnits: UITextField!
var intTotalUnits:Int? = Int(fldTotalUnits)
The error here says "Cannot use instance member 'fldTotalUnits' within property initializer;..."
I tried replacing var with let, I tried NSString, I tried .toInt() but nothign worked... so how do I this?
String to Int conversion is not complicated. You simply do the conversion at the wrong place. You are trying to reference one member in the initialization of another member, that is not allowed. In this particular case simply because fldTotalUnits has the value nil when you would try to use it via Int(fldTotalUnits). When creating an instance of your class ViewController fldTotalUnits is set to nil and initialized with a useful value later. Therefore what you have to do in the first place is move the line into a separate method:
func doSomething() {
var intTotalUnits:Int? = Int(fldTotalUnits)
}
Now you will see that the compiler complains about there not being a suitable initializer because you have to access the text property of fldTotalUnits instead of using the actual textfield:
func doSomething() {
var intTotalUnits:Int? = Int(fldTotalUnits.text!)
}
Now you can think about moving the declaration of intTotalUnits to somewhere else, but setting its value has to happen in some method.
The code in your question is trying to create an Int from a UITextField, not a String. What you should say is something like…
var intTotalUnits:Int?
func updateTotalUnits()
guard let text = fldTotalUnits.text else { return }
intTotalUnits = Int(text)
}