When my app gets back to its root view controller, in the viewDidAppear:
method I need to remove all subviews.
How can I do this?
When my app gets back to its root view controller, in the viewDidAppear:
method I need to remove all subviews.
How can I do this?
Edit: With thanks to cocoafan: This situation is muddled up by the fact that NSView
and UIView
handle things differently. For NSView
(desktop Mac development only), you can simply use the following:
[someNSView setSubviews:[NSArray array]];
For UIView
(iOS development only), you can safely use makeObjectsPerformSelector:
because the subviews
property will return a copy of the array of subviews:
[[someUIView subviews]
makeObjectsPerformSelector:@selector(removeFromSuperview)];
Thank you to Tommy for pointing out that makeObjectsPerformSelector:
appears to modify the subviews
array while it is being enumerated (which it does for NSView
, but not for UIView
).
Please see this SO question for more details.
Note: Using either of these two methods will remove every view that your main view contains and release them, if they are not retained elsewhere. From Apple's documentation on removeFromSuperview:
If the receiver’s superview is not nil, this method releases the receiver. If you plan to reuse the view, be sure to retain it before calling this method and be sure to release it as appropriate when you are done with it or after adding it to another view hierarchy.
UIView
returns a copy of the subviews
mutable array, so this code just works. Completely different story on the desktop, where the same code will throw an exception. See #4665679 –
Bugger UIView
. It is NSView
that allows setting them externally. –
Bugger someUIView.Subviews.All( v => { v.RemoveFromSuperview(); return true; } );
. IMHO cleaner to say what you mean: someUIView.Subviews.ToList().ForEach( v => v.RemoveFromSuperview() );
. –
Berni Get all the subviews from your root controller and send each a removeFromSuperview:
NSArray *viewsToRemove = [self.view subviews];
for (UIView *v in viewsToRemove) {
[v removeFromSuperview];
}
self.view
as you have. –
Bugger for (UIView *v in [self.view subviews])
its easier –
Jannery In Swift you can use a functional approach like this:
view.subviews.forEach { $0.removeFromSuperview() }
As a comparison, the imperative approach would look like this:
for subview in view.subviews {
subview.removeFromSuperview()
}
These code snippets only work in iOS / tvOS though, things are a little different on macOS.
(subviews as [UIView]).map { $0.removeFromSuperview() }
–
Splenitis .map
. this is a pure side effect and is better handled like this: view.subviews.forEach() { $0.removeFromSuperview() }
–
Marvin If you want to remove all the subviews on your UIView (here yourView
), then write this code at your button click:
[[yourView subviews] makeObjectsPerformSelector: @selector(removeFromSuperview)];
This does only apply to OSX since in iOS a copy of the array is kept
When removing all the subviews, it is a good idea to start deleting at the end of the array and keep deleting until you reach the beginning. This can be accomplished with this two lines of code:
for (int i=mySuperView.subviews.count-1; i>=0; i--)
[[mySuperView.subviews objectAtIndex:i] removeFromSuperview];
SWIFT 1.2
for var i=mySuperView.subviews.count-1; i>=0; i-- {
mySuperView.subviews[i].removeFromSuperview();
}
or (less efficient, but more readable)
for subview in mySuperView.subviews.reverse() {
subview.removeFromSuperview()
}
NOTE
You should NOT remove the subviews in normal order, since it may cause a crash if a UIView instance is deleted before the removeFromSuperview
message has been sent to all objects of the array. (Obviously, deleting the last element would not cause a crash)
Therefore, the code
[[someUIView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
should NOT be used.
Quote from Apple documentation about makeObjectsPerformSelector:
Sends to each object in the array the message identified by a given selector, starting with the first object and continuing through the array to the last object.
(which would be the wrong direction for this purpose)
removeFromSuperview
finishes, the UIView will be removed from the array, and if there are no other living instances with a strong relation to the UIView, the UIView will also be deleted. This may cause an out of bound exception. –
Wynny [yourView subviews]
returns a COPY of the array, therefore is safe. (NOTE that on OSX, what you say is correct.) –
Berni Try this way swift 2.0
view.subviews.forEach { $0.removeFromSuperview() }
forEach
based solution was added after yours, I missed that. Apologies. –
Holleran view.subviews.forEach { $0.removeFromSuperview() }
Using Swift UIView
extension:
extension UIView {
func removeAllSubviews() {
for subview in subviews {
subview.removeFromSuperview()
}
}
}
In objective-C, go ahead and create a category method off of the UIView class.
- (void)removeAllSubviews
{
for (UIView *subview in self.subviews)
[subview removeFromSuperview];
}
Use the Following code to remove all subviews.
for (UIView *view in [self.view subviews])
{
[view removeFromSuperview];
}
In order to remove all subviews Syntax :
- (void)makeObjectsPerformSelector:(SEL)aSelector;
Usage :
[self.View.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
This method is present in NSArray.h file and uses NSArray(NSExtendedArray) interface
If you're using Swift, it's as simple as:
subviews.map { $0.removeFromSuperview }
It's similar in philosophy to the makeObjectsPerformSelector
approach, however with a little more type safety.
map
should not result in side effects. Plus, the same result can be achieved via forEach
. –
Holleran For ios6 using autolayout I had to add a little bit of code to remove the constraints too.
NSMutableArray * constraints_to_remove = [ @[] mutableCopy] ;
for( NSLayoutConstraint * constraint in tagview.constraints) {
if( [tagview.subviews containsObject:constraint.firstItem] ||
[tagview.subviews containsObject:constraint.secondItem] ) {
[constraints_to_remove addObject:constraint];
}
}
[tagview removeConstraints:constraints_to_remove];
[ [tagview subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
I'm sure theres a neater way to do this, but it worked for me. In my case I could not use a direct [tagview removeConstraints:tagview.constraints]
as there were constraints set in XCode that were getting cleared.
In monotouch / xamarin.ios this worked for me:
SomeParentUiView.Subviews.All(x => x.RemoveFromSuperview);
In order to remove all subviews from superviews:
NSArray *oSubView = [self subviews];
for(int iCount = 0; iCount < [oSubView count]; iCount++)
{
id object = [oSubView objectAtIndex:iCount];
[object removeFromSuperview];
iCount--;
}
iCount++
and iCount--
, leaving the index the same, so it will be an infinite loop if [oSubView count]>0
. This is definitely buggy and NOT USABLE code. –
Wynny © 2022 - 2024 — McMap. All rights reserved.