Assign Arguments to viewDidLoad function - swift4

Can I assign arguments to the override fun viewDidLoad() ? I want to send String variable from another function to the viewDidLoad.

No viewDidLoad() is a built in function that fires when the view has loaded.
You can save it in a global or data, or pass it with a notification, maybe even to a custom function rather ...etc

Related

Reusable Custom UI View w/ Parameters

I have created a custom subclass of a UIView that has a Label, Image & Text Input w/ a custom .xib file. The class is meant to be an item that can easily be reused to generate a form. The Label is simply a title that goes above the Text Input & the Image is a custom icon that is shown/hidden based on if the field is required. Right now in the form, I am building it out like so :
Instantiate a UINib of my Custom View
Set the text of the label
Add the instance of the UINib to an array
After the array is built out, iterate through each item, cast it as UIView, add as a subview, and finally add constraints
My issue is this - ideally I'd like to make a custom init function where I pass in 2 parameters : Title (for the label) and a Boolean (for if it's required). I tried making a separate init, but when running the simulator, nothing appeared. It seems like I need to call the UINib(...).instantiate(...) function in order to have the actual view appear; however, I can't figure out how to assign variables during that initialization. I appreciate any feedback/suggestions/resources/etc. Thank you!
You can write a convenience init, where you call self.init first and then apply your parameters in convenience init to your views like:
convenience init(title: String, isRequired: Bool) {
self.init()
titleLabel.text = title
titleLabel.isHidden = isRequired
}

Passing variable in viewDidLoad() or ViewDidAppear() to button action

I have a complex variable that I look up from a Firestore Document but that is not important. It works perfectly in either viewDidLoad or viewDidAppear. I can print it to verify the variable has the correct value.
let q1 = data!["q1"]! as? Bool ?? true
When I call the variable in the if statement in the button action I get the following error:
Use of unresolved identifier 'q1'
print(q1)
But print(q1) works perfectly if run in the viewDidAppear.
Can someone tell me what I am doing wrong? How can I pass a variable from viewDidLoad to the button action?
How can I pass a variable from viewDidLoad to the button action?
Store the value in an instance property. Properties are global to all methods, so viewDidLoad can see it (to store the value in it) and the button action method can see it (to retrieve and use it).

Best place to unwrap optional instance properties--when created or when called?

When you want to create an instance property that has an initializer that you want to initialize after self is available, you typically would make it a variable and declare it as an option, like so:
var mapView: MGLMapView?
And then when self is available, you would initialize it, like so:
mapView = MGLMapView(frame: view.bounds)
However, when you later call mapView, should you call it with ? or !
mapView?.userTrackingMode = .follow
mapView!.userTrackingMode = .follow
Or should it be unwrapped right when the property is first created, like so:
var mapView: MGLMapView!
And then forego any use of ? or ! thereafter. All three possibilities will compile and run so is there a best practice or rules of thumb to follow when having to choose?
A variable should be declared as implicitly unwrapped (using !) only when you will be assigning a value outside of an init but before all of your other code will access the variable, and the variable will definitely be given a value.
Typical examples of this are outlets in a view controller. The values are assigned after init but before all other code will make use of them. In this case awakeFromNib or viewDidLoad is a typical place for the initialization. Since all other code can safely assume the variable has a non-nil value, the use of the implicitly unwrapped variable makes sense.
For "normal" optionals (using ? in the declaration), you should never force-unwrap those value since the whole reason the variable is an optional is because it might be nil.
In these cases, always use conditional binding (if let) or optional chaining.
In your example, you will most likely setup the map view in the viewDidLoad method so declare it as var mapView: MGLMapView!. Then you can reference mapView like it's not an optional everywhere else in your code. Just make sure you don't attempt to access mapView before viewDidLoad initializes it.
Another option is to set up the property as a lazily loaded property. Then you don't need it to be declared with either ? or !.
If we assume that MapView will be initialized when controller loads, we can then also assume that all subsequent references will not be nil and that we can implicitly unwrap MapView.
Therefore a valid approach is to declare mapView as follows
var mapView: MGLMapView!
This is referred to as an implicitly unwrapped option and then you may reference it directly as below (provided there is no possibility of mapView being set to nil elsewhere)
mapView.userTrackingMode = .follow
There is a section in the Swift Programming Language by Apple entitled "Implicity Unwrapped Optionals" which will go into further detail.
You can also write code other ways as you have indicated - the important thing to consider is whether or not there is a possibility of the mapView variable being nil when it is unwrapped. If not, use above.
You will also notice that the interface builder within XCode also makes use of implicitly unwrapped variables when referencing UI components (labels, textboxes, etc) which gives me confidence that this is an appropriate approach.

Does defining functions inside viewdidload() save more memory versus defining them outside?

Since viewdidload() is only called once in the lifecycle of that instance of the UIViewController object, does that mean that this example below is a "bad practice" since setBackgroundColor(), a function that is only called once, is unnecesarrily loaded into the memory of the entire class when it really should just exist entirely (defined and called) inside viewdidload()? Or in terms of efficiency, does it not matter where setBackgroundColor() is defined and called?
class MasterViewController: UIViewController {
func setBackgroundColor() {
self.view.backgroundColor = UIColor.green
}
// Do any additional setup after loading the view, typically from a nib.
override func viewDidLoad() {
super.viewDidLoad()
setBackgroundColor()
}
// Dispose of any resources that can be recreated.
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Making a function local to a method changes its scope, but not the lifetime of code compiled from it. Same goes for methods of the class: their binary codes are not managed individually, at least not at this time. This is not a big deal, though, because executable code of your function is relatively tiny.
What matters here is that the function name is not visible in its outer scope, letting other methods define their own setBackgroundColor() functions unrelated to the one defined within viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
// Nested function definition
func setBackgroundColor() {
self.view.backgroundColor = UIColor.green
}
// Calling nested function
setBackgroundColor()
}
This improves readability, because function definition is right there at the point where it is used. It also improves maintainability, because whoever is refactoring your code can be certain that there can be no other uses of setBackgroundColor outside of viewDidLoad.
Of course, this is just an example. The nested function is not necessary here - you can rewrite it without setBackgroundColor function, like this:
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.green
}
It's not a case of memory usage, it's a matter of loading the view efficiently.
UIViewControllers control views. But the views isn't created at the same time as the view controller.
Setting the background colour, indeed, any kind of view configuration, in viewDidLoad is done because when that method is called, the view has been created (although not necessarily displayed) at a convenient point in the view controller's life cycle. If you created the view controller and then called your setBackgroundColor method, the self.view part of the call would cause the view to be created straight away if it hadn't already been created.
For certain methods, such as view controller presentations, this allows the creation methods to return as quickly as possible without the view being loaded straight away and keeps the UI responsive.
It's because of this lazy loading of views that UIViewController has the isViewLoaded parameter which returns a Bool for whether the view is loaded into memory or not, but without causing the view to load.
I don't see anything in your code that warrants a memory concern. Micro-optimization is greatest time waster in software development. But since you asked, viewDidLoad is invoked only once. From Apple's Work with View Controllers:
viewDidLoad()—Called when the view controller’s content view (the top of its view hierarchy) is created and loaded from a storyboard. The view controller’s outlets are guaranteed to have valid values by the time this method is called. Use this method to perform any additional setup required by your view controller.
Typically, iOS calls viewDidLoad() only once, when its content view is first created; however, the content view is not necessarily created when the controller is first instantiated. Instead, it is lazily created the first time the system or any code accesses the controller’s view property.
My guess is that any loss in efficiency is worth the gain in having more readable code. In fact, a compiler optimization may even inline the function if you mark it as private. I don't know enough about the Swift compiler (LLVM) to know if this is definitely true but it may be.
Martin Fowler has a great article on function length in which he states that he has many functions that are one line long simply because they make the code easier to understand.
Some people are concerned about short functions because they are worried about the performance cost of a function call. When I was young, that was occasionally a factor, but that's very rare now. Optimizing compilers often work better with shorter functions which can be cached more easily. As ever, the general guidelines on performance optimization are what counts.
Not sure if his notes about function caching apply to Swift, but he also says:
If you have to spend effort into looking at a fragment of code to figure out what it's doing, then you should extract it into a function and name the function after that “what”. That way when you read it again, the purpose of the function leaps right out at you
In general, I wouldn't focus too much on optimization unless you notice that it's a problem. YAGNI
... And as Code Different noted, yes ViewDidLoad() is only called once.

Update drawRect using display() within an NSSliderCell?

I have a drawRect display which plots a graph and I am attempting to change the parameters using a slider. In Objective-C I would use a slider action and include [self display] to update the display. This is the code in Swift which does nothing (the parameter is "freq"):
#IBAction func freqValue(sender: NSSliderCell) {
freq = Float(sender.doubleValue)
display()
}
Any ideas why it doesn't work? Thanks!
You should avoid calling display directly, both in Objective-C and in Swift. Instead, you should do
self.needsDisplay = true
This schedules drawing at the next runloop iteration. Calling display is only needed in some very rare special cases.