When creating UIs in IB I have often used buttons that have an action but there is no reason for the view controller to access this button.
The button text never changes, the button image never changes, it never moves, etc...
Because of this I don't give it an IBOutlet property and I don't connect it up to anything in the VC (other than the action of course).
There is a similar question on SO that I've read and the arguments on there go into memory management issues. That question is from early 2011, before ARC. Given that all my IBOutlet properties are weak anyway the memory is dealt with by their superview not by the view controller. So the issues mentioned in that question are now moot.
Is there a reason to connect them up now? Should they always have a connection? If so, why?
Short answer: no.
IBOutlets are needed to refer to elements of the UI.
If you don't need to access to such elements, you don't have to connect them with a IBOutlet
Answer is NO.
But here's a valuable tip, if someone sees this question/answer and goes gung ho and deletes all the unused IBOutlets.
If you remove an IBOutlet for a UIElement, make sure that the UIElement in the IB is not referencing to the now non-existant outlet. Otherwise, you'll have some weird crashes, that'll take quite some time to be resolved.
This is an issue that has had me in a soup many times. I am not sure if this has been fixed in the latest versions of Xcode, but its safer to check.
Related
TL;DR: I have an IBOutlet (UILabel) that is properly connected in Storyboard. Accessing (unwrapping) it works fine in viewDidLoad() ... but a few seconds later its value is nil. A watchpoint says that the outlet changes right after a call to viewDidLayoutSubviews(), but... a print() call at the end of viewDidLayoutSubviews() shows it non-nil.
This is very similar to IBOutlet is nil but his solution (track value with didSet()) did not work. (There are many related posts but all had trivial solutions.)
What I have done:
Reconnected the outlet to the Label — from both sides
Deleted the Label and reconnected it
Cleaned the project
Deleted the DerivedData
Quit and restarted Xcode
Quit and restarted my Mac
Added a didSet() method to the outlet.
It triggers during viewDidLoad() and shows a non-nil value.
In viewDidLoad() I set its text value with no problem
It does not trigger before the nil-unwrapping crash
Added a watchpoint to the variable.
This does trigger before crash (right after viewDidLayoutSubviews() and shows the following:
As mentioned before, at exit of the most recent method call before the watchpoint (viewDidLayoutSubviews()) the outlet is non-nil.
These crashes seem always to involve subviews of a particular superview. I added a watchpoint to the superview's outlet but it never triggers.
What could be inciting my code to let go of this weak reference?
TL;DR: I was clobbering the relevant views.
Well, the best way to find your own answer is to ask someone else. Thanks to #DonMag, I was preparing more traces, breakpoints, and screen shots. I noticed this method (added to fix another bug, of course):
Of course, the two views that were becoming nil were subviews of centralOverlay. Ones I wanted to keep.
So I guess my answer was similar to that of IBOutlet is nil — pilot error — except the didSet() handler did not solve the mystery.
I guess i might not understand how memory deallocates in Swift properly and thats why i wanted to ask this:
If i create a Message to the user using a UIView with a Label. i show it with an animation and then use ".removeFromSuperview()". when does it's memory deallocates? what are the conditions for it to deallocate?
Im asking because if it doesn't deallocate until the app closes - it means that for the run of the app - each message shown and then hidden will take up memory for no good reason.
Thanks for anyone who explains :)
Views maintain a strong reference to their subviews. Once the subview is removed, the superview relinquishes this reference. If you have no other strong references the retain count will decrement to zero and the view will be released.
I am new to IOS development and have a question.
I wanted to know what is the role of the Outlet and Action in IOS development?
I have tried searching online but just found examples. I wanted some background information about this so I have better knowledge on Outlets and Actions before I dig into coding.
I would appreciate it if someone could explain this to me or direct me to an online source.
Thanks in advance.
An IBOutlet a way to mark a property that is defined (usually) within your UIViewController (or descendant) to allow access to/from a view object created within the Interface Builder (hence the "IB").
An IBAction a way to mark a method that is defined (usually) within your UIViewController (or descendant) to allow access to/from a view object (UIButton, etc) created within the Interface Builder (hence the "IB").
have a look here, very well explained. With 2 minutes of time, you've found it by yourself.
NSHipster
I have a UIScrollView full of tacos.
I attached a pull-to-refresh handler to it via: https://github.com/samvermette/SVPullToRefresh
It extends uiscrollview, and exposes this method:
[scrollview addInfiniteScrollingWithActionHandler:^{
// Get me more tacos
}];
When InfiniteScrolling is triggered, I clear the scrollview's subviews and data array(intentionally) and replace it with a new set.
It works great the first time. However, when I want to load more tacos it crashes.
I get:
-[SVInfiniteScrollingView retain]: message sent to deallocated instance 0x1e5db5d0
Not surprisingly, if I leave 1 subview left in my UIScrollview, everything works fine.
Question: How can I fix this?
I thought about declaring my properties with a strong pointer, like:
#property (strong, nonatomic) IBOutlet tacoScroller *tacoScroller;
But, I worry about a retain cycle & it also doesn't work.
Any help would be appreciated, perhaps I'm missing something fundamental.
Edit:
I'm using ARC
Use an UITableView to show your tacos, this way you will reuse views and avoid wasting memory. Also it is the easiest and most convenient way to show a list of things.
One simplest solution according to your description is simply add an empty & hidden subview inside the scrollview, i am sure it wont occupy much amount of memory.
I think you are invoking the wrong method. Infinite scrolling is for other purposes.
You probably want to use
[scrollView addPullToRefreshWithActionHandler:^{ ... }];
Also, as others pointed out, you definitely should consider to use a UITableView to present your data, which seems to be very suitable for the task.
Fairly straightforward question in two parts.
If a view retains its subviews, and we create a view hierarchy in Interface Builder where views are nested within others, why does the IBOutlet property for the nested subviews need to be set to retain? Wouldn't assign be an acceptable parameter for those subview properties?
I have a UIView subclass which adds a few subviews to itself upon initialization. To capture references to specific subviews, #property (nonatomic, assign) will suffice for that need, correct? For example, the main UIView adds a player score subview, then later wants to talk to that player score to update it. That reference only needs to be assigned, as the view proper is automatically retain by the UIView class, right?
1) It doesn't need to be. assign is fine. What made you think that you have to use retain?
2) Yes
By the way, are you using ARC? If so, use weak instead of assign (please don't ask why, it is well explained in every corner of stack overflow and the Internet in general).
Yes, it is true that in your case the subview will be retained by the view, so we don't technically need to retain it again. However, that is kind of fragile. What if in the future you add some code that removes that subview from its superview? Then you have a dangling pointer unless you make sure to nil it out.
It is general convention to retain instance variables, unless it is necessary not to (e.g. for delegates). If we go down the path of saying "oh we don't need to retain this instance variable because it's retained here; oh we do need to retain this other one because it's not retained; etc.", then we end up with very haphazard memory management, where every time we add an instance variable, we have to go and think about whether it is retained by something else or not; and then every time we use it, we have to remember whether we decided to retain it or not. It is precisely the kind of memory management nightmare that the memory management rules are designed to avoid.
And retaining the instance variable, what harm does it do? In this case, it just causes an additional retain and release when we assign it. Not a big deal, for the benefit of simplicity and consistency.