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)
}
Related
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.
I'm trying to move the logic of a viewController to a view model but for some reason it always crashes, saying unexpectedly found nil while unwrapping an Optional value. I constantly get this error no matter what code I try to move, so I must be doing something fundamentally wrong. Here's a sample of the code I have in the viewController:
var recipesViewModel: RecipesViewModel! //VIEW MODEL CLASS REFERENCE
var recipeCategory = recipesViewModel.transformToUpperCase(dataRecieverStringRecipeView: "testString")
Then in the view modelclass:
func transformToUpperCase(dataRecieverStringRecipeView: String) -> String {
var recipeCategory = dataRecieverStringRecipeView
var prefixRecipeCategory = recipeCategory.prefix(1).uppercased()
var dropFirstRecipeCategory = recipeCategory.dropFirst()
var upperCasedRecipeCategory = prefixRecipeCategory + dropFirstRecipeCategory
return upperCasedRecipeCategory
}
...it translates the string to have an uppercase letter as its first letter.
The code works perfectly fine when everything is in the view model, but as soon I move it to another class and call the function through an object it crashes. What am I missing?
You need to fix your view model class reference
Line to change:
var recipesViewModel: RecipesViewModel!
Replacement Line:
var recipesViewModel = RecipesViewModel()
This line of code will properly declare/create recipesViewModel as an object of class RecipesViewModel.
Hope that resolves your inquiry!
var recipesViewModel: RecipesViewModel! does not instantiate a new object. Put the category function back in your RecipesViewModel class, then change the variable declaration to:
Declaration
var recipesViewModel: RecipesViewModel!
Later on
recipesViewModel = RecipesViewModel() //or whatever initializer you need.
Edit
As rmaddy pointed out: you probably can ditch the ! and use var recipesViewModel: RecipesViewModel = RecipesViewModel() instead if you don't have any failable initializers or this isn't a runtime injected property and just put it as a 1-liner:
var recipesViewModel: RecipesViewModel = RecipesViewModel()
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)
Ok, I'm probably missing something super basic. I have an instance property called currentValue, initialized to be a String.
class ViewController: NSViewController {
var currentValue = ""
// ...
func getNewValue() {
currentValue = computeNewValue()
aLabel.stringValue = currentValue
}
func calledLater() {
println("\(currentValue)")
}
}
When I call getNewValue(), the label updates correctly.
But, when I call calledLater(), the currentValue is "reset" to an empty string.
At first I thought it was a weak storage thing but Swift apparently defaults to strong storage?
I tested this by initializing currentValue to "a" and, again, the label updates correctly, but when I get the variable later it returns "a".
I feel like I'm missing something but can't word it in a way that will let me do correct research.
You might be calling the methods on different instances of your 'ViewController' class.
(A typical scenario is when loading controllers from a storyboard; it "looks" like instances in the storyboard, but they are really just blueprints.)
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.