Swift, two issues. 1) weak var 2) bang operator for #IBOutlet - swift

Per:
#IBOutlet weak var nameLabel: UILabel!
Whenever I declare my IBOutlets, i just use var instead of weak var. But I've recently come across a few code templates that use weak var. Why do they do it? What's the added benefit?
Why is there a bang operator at the end of UILabel. I know it's required and i go along w/ it, but just asking it now.
Thanks in advance.

Swift IBOutlet are weak by default (but others properties are strong by default). So both writing are the same.
You have more details about the difference between weak and strong here
According to apple documentation
When you declare an outlet in Swift, you should make the type of the
outlet an implicitly unwrapped optional (!). This way, you can let the
storyboard connect the outlets at runtime, after initialization.

The outlets are weak since the view elements are owned (strongly) by the view. I think it's technically OK for your view controller to have a strong reference too, but not necessary.
Weak variables are optional since they can be nil. You can declare your outlets with ? instead but that means using force-unwrapping or optional binding every time. Declaring them as implicitly-unwrapped optionals with ! is just a convenience.

You use weak when referring to IBOutlets because so long as the object remains in its superview there will be a strong reference to it. See weak or strong for IBOutlets.
Next, the bang operator indicates that the IBOutlet is an explicitly unwrapped label. With the bang operator, it guarantees that the object will exist, so when referencing it, you can simply reference it like this:
someLabel.text = "some text"
However, you can make them IBOutlets optional:
#IBOutlet weak var someLabel: UILabel?
But you must use ? when accessing them
someLabel?.text = "some text"

#gregheo's response is the best explained, to further elaborate: if you consider ownership in this situation the View object referred to by the #IBOutlet usually shouldn't be owned by the View Controller referring to it.
Rather it should be owned by its superview wherever it may be in the tree (which happens strongly by UIView.subviews). The View Controller instead owns the very root of it's View Tree strongly (UIViewController.view). weak explicitly declares a non-owning reference that may become nil at different points in the View Controller's life.
Here I would offer an alternative to using !: using an implicitly unwrapped optional reference is a dangerous practice that weakens the tools Swift offers us. A View Controller which is loaded from Xib or Storyboard includes in its lifetime a regular time after being created and before it's View has been loaded where the #IBOutlet reference is nil, every time. To assume no one will operate on the member during that time means not using the Swift grammar and compiler's feedback to our advantage.
Additionally #IBOutlets are a powerful tool that enables a flexible, visually focused approach when designing a screen or view. It is common practice to have your View Controller expose #IBOutlets for all information it has available, regardless of whether or not it is known that it will be used and separately deciding which to actually connect and use when building and iterating on the View from within Interface Builder.
Additionally-additionally if your View should be flexible enough to be instantiated from Xib/Storyboard AND from code, depending on how you decide referenced subviews should be instantiated and connected they may or may not be available immediately.
For the reasons above I define mine: #IBOutlet weak var nameLabel: UILabel?

Related

Understanding weak and unowned reference in Swift under the hood

I want fully understand what going inside weak and unowned referance in Swift.
For this i read MikeAsh and got some questions.
What already known:
when there is no weak (and, i suppose, unowned) object reference, the strong reference counter is stored directly in the memory area of the object
when a weak link appears, the second word in the object memory is reused to reference the side table
side table has link to the object
weak link refers to this side table
And what i want to clearify:
What else side table store inside except link to the object and number of strong reference?
Is unowned reference link to the side table too? If not and unowned link refers to the object memory what about performance between weak and unowned ?
Okay, i found out.
Unowned link points to the object as well as strong.
Unowned link faster than weak.
Side table stores strong RC, weak RC, unowned RC, link to the object and some flags

Swift performance on optional UI elements

Setting up a UILabel in Swift I can do the following
#IBOutlet var wLabel: UILabel!
or
#IBOutlet var wLabel: UILabel?
Setting the text I can either do
wLabel.text = "..."
or, for the latter do
wLabel?.text = "..." // with a question mark for the optional
Keeping them optional will help for the case when they are unexpectedly nil as it will just skip this call then and go ahead with the code. Having them declared with the ! would crash the app if the label was nil.
Now why would you not make everything optional? The only reason I could think of would be for better performance. Should I stay away from having them optional if my app has a lot of UI elements so them being optional would mean a disadvantage regarding performance? I wasn't able to find any information on this anyhere.
Using ? in your Outlet will make your code untracable
Crashes are very good in some scenarios, because if no crash is there then it becomes super difficult to trace even small error.
Consider the examples of #IBOutlet with !:
#IBOutlet var wLabel: UILabel!
wLabel.isEnabled = true
Just remove the connection of your Outlet label from your storyboard and run the app, your app will crash on wLabel.isEnabled = true. Since you got a crash so you can got to your storyboard see whether the connection is proper or not. In case there is no connect you add it and damn! you solved the problem easily.
Now consider the examples of #IBOutlet with ?:
#IBOutlet var wLabel: UILabel?
wLabel?.isEnabled = true
Do the same thing, just remove the connection of your Outlet label from your storyboard and run the app, your app won't crash at all. You won't be able to know the error, hence making your code a mess and untracable.
Apple guys were very aware of optional thing, they did force unwrapping of #IBOutlet for a reason. And of course there is no performance difference between ! and ?
If you're setting something up as an outlet it's set up as a force unwrapped optional (with exclamation mark !) because Swift requires your classes to have all of their properties initialized when the object is constructed (i.e. init method is called). Outlets are not created during object construction but rather assigned later when the xib or storyboard data is loaded into your component. Force unwrapped optionals are basically a way to say that you guarantee that the property will be initialized after object's init is called and before they're used.
There are no performance gains to using either of these. An Optional? type means that the property can either be nil or have a value. A force unwrapped optional ! means that the property is guaranteed to have a value when it is used. Upholding this is up to the developer and using such property if its value is nil will result in a crash.

Non optional IBOutlet returns Fatal error: when referenced from another UIViewController class

I have a UIView defined in
class InteractViewController: UIViewController {
#IBOutlet weak var tipsView: UIView!
var tipslayer: CALayer {
return tipsView.layer
}
}
There are a number of constraints also attached in the class as well as labels for example.
#IBOutlet weak var tips1Top: NSLayoutConstraint!
#IBOutlet weak var tips1Right: NSLayoutConstraint!
#IBOutlet weak var tipsTitle: UILabel!
#IBOutlet weak var tipsDesc: UILabel!
All are connected on the storyboard to their correct outlets. Referencing these within the actual InteractViewController itself I am able to adjust opacity, update labels on the layer etc.
However, these are not needed unless the user is first using the application so a simple if else on the InteractViewController calls a function to either display and update properties of these or not show them at all.
The function that controls and updates these properties is in another class (Swift file in the project called.
class TipsViewController: UIViewController {
func tips() {
InteractViewController().tipslayer.transform = CATransform3DMakeScale(0.8, 0.8, 1.0)
}
}
Causes the app to crash creating
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
on
return tipsView.layer (the InteractViewController)
tipsView and tipslayer are of cause not optionals and are not declared as optionals.
I have three questions I hope I can get assistance with.
Is having the physical reference to the outlets on the ViewController class InteractViewController: UIViewController the problem? If so is it because they are supposed to be programmatically added instead on the class TipsViewController: UIViewController (which does not have a physical visual view controller in Xcode)?
Does having a physical reference to the outlets on the
class InteractViewController: UIViewController
create unnecessary memory use if on InteractViewController the call to the function on the second ViewContoller TipsViewController.tips() is never called so in other words the answer to question 1 is essentially any physical outlets should be programmatically added on lass TipsViewController: UIViewController?
If there is no memory issue and knowing that tipsView and the returning tipslayer are not optionals why am I simply unable to reference them from the tips() function in the other class (TipsViewController: UIViewController)? I have seen multiple posts about "passing data between view controllers" but I am not passing data between variables or arrays. I want/ need to simply update label string, constraints (objects in one view controller class from another view controller class.
I know people are busy so just to say in advance I appreciate all feedback and assistance with the problem.
It was suggested that my question was a duplicate of [What does "fatal error: unexpectedly found nil while unwrapping an Optional value" mean?
But this is not my question. MY question relates specifically to accessing an Outlet from another ViewController which is then generating a Nil response to the Outlet because as explained InteractViewController is apparently not referencing the ViewController. Please read the explanations and answer provided by Rob which answers this specific question.
Your title says "IBOutlet returns Fatal error: when referenced from another UIViewController class". The bottom line is that one view controller should never access another view controller's outlets.
In your code snippet, you employ the InteractViewController() syntax. Unfortunately, this just instantiates view controller, but does not hook up outlets in storyboard. You need to instantiate via storyboard and, even then, you can’t reference your outlets immediately, but only after viewDidLoad is called later. Only the view controller itself should be trying to access its own outlets, anyway.
The TipsViewController() or InteractViewController() syntax says "create a new, blank instance of that view controller". It's equivalent to saying TipsViewController.init() or InteractViewController.init(). And, worse, it's not using the storyboard at all (and thus no outlets will be hooked up). That's not what you want. You should avoid using this ViewController() syntax, as outlets will never been accessible that way.
InteractViewController should determine whether TipsViewController should be presented (e.g. checking user defaults), and if so, present it. The only thing InteractViewController should do, though, is:
figure out whether to present TipsViewController;
if so, present that TipsViewController; and
pass model data (e.g. whatever InteractViewController retrieved from UserDefaults) to the TipsViewController instance that is created for you.
But anything and everything about how TipsViewController presents its subviews, is the purview of TipsViewController alone. InteractViewController should never interact directly with any outlets of TipsViewController.

SceneKit crashes when I use constraint and minimize App

I have very strange behavior in my app, that I can't explain. I have a SceneKit session running, and some nodes have constraints assigned (no matter what kind). When app goes to background I'm removing all nodes from the scene, and when it appears again I'm adding them again (This is needed for reasons not needed here). When I have this constraints assigned and resume app - it crashes. Not always, but very often. I have no idea what to do to fix this. I tried removing constraints when removing nodes, but this did not help. The error I get is in a screenshot. Can someone help me find a solution?
Your question doesn't show the code that you are referencing, but I can tell you that an EXC_BAD_ACCESS error typically means you are trying to access an object that has been released from memory.
Without going in depth about strong vs. weak variables, you likely have a weak or unowned variable (to that constraint) that is becoming nil and that you are trying to access (by force-unwrapping).
When you are removing these nodes, or when the view disappears, the constraint is released from memory. So the fix here is to either make the reference to this constraint strong or to make a new constraint, keep a strong reference to that in the class, and assign that constraint to the object.
Assuming your reference is to a storyboard, replace:
#IBOutlet weak var constraint: NSLayoutConstraint!
With:
#IBOutlet var constraint: NSLayoutConstraint!
Also note that the variable is probable force-unwrapped (NSLayoutConstraint!), which is likely why you are running into the EXC_BAD_ACCESS error. Set your constraint to be a strong variable instead of weak, or better yet, avoid force-unwrapping optionals if possible!
Note: If this doesn't solve your problem, leave a comment after adding more details to your question.

Swift: How to define a UIView delegate with unowned(unsafe) reference?

I find the following code in UITableView class,
unowned(unsafe) var delegate: UITableViewDelegate?
so I wander how to define a unowned(unsafe) reference delegate for UIView, then I encounter the following error when I write the unowned(unsafe) keyword in my class,
/Users/larryhou/Documents/Xcode/AtomicElements/AtomicElements/AtomicElementView.swift:32:25: 'unowned' cannot be applied to non-class type 'AtomicElementViewDelegate?'
protocol AtomicElementViewDelegate:NSObjectProtocol
{
func didTap(target:AtomicElementView, sender:UITapGestureRecognizer)
}
I can only use weak keyword, but I want keep the reference until UIView is deallocated.
Those two designations - unowned and weak - are equivalent from the perspective of references. Where they differ is the presumption of existence - in Swift, unowned instances are presumed to always exist as long as reference to them does, whereas weak instances are optionals - they may exist, or they may not, so you need to use optional chaining or some other means of working with them.
In UIKit, the delegate pattern with UIView subclasses is to declare them as weak because the delegate is nearly always the view controller that owns the view that the subclass is a subview of. Declaring a delegate as strongly referenced in that situation would set up a reference cycle, hence delegates are typically declared with the weak keyword. If you have a different situation, you can allow your delegate to be strongly referenced by simply leaving out the weak keyword.
In this particular case, unowned (unsafe) is an artifact of being bridged from ObjC.
how to define a unowned(unsafe) reference delegate for UIView
You can't. And you shouldn't want to. unowned(unsafe) is a way of expressing the Objective-C non-ARC assign policy, i.e. no memory management. It is horrible and dangerous (and can cause crashes). The name tells you what the problem is. It is unsafe!!! There is no Swift equivalent because Swift has built-in memory management. This is one of the reasons why Swift is good. Don't worry be happy.
But do be careful, because this designation is warning you that if the delegate goes out of existence while the UITableView still exists, you will crash because the table view will not know this and may try to send a message to the non-existent delegate.