How to find number of subviews? - ios

I have a Xcode project and in it i have dragged two views and both of them inherit from a class LabelsView. However when I try and run the code to find out number of subviews, I get 4. Can anyone explain why is this happening.
The code is
NSLog(#"no. of subviews:%#",[NSString stringWithFormat:#"%d",[self.superview.subviews count]]);

You're probably getting a weird subview count because you're accessing self.superview.subviews. You likely just want self.subviews.
If, like you said, you only care about subviews of type LabelsView, you can filter those out like this:
int labelViewCount = 0;
for(LabelsView *subview in self.subviews) {
if([subview isKindOfClass:[LabelsView class]]) {
labelViewCount++;
}
}
NSLOG(#"label count: %d", labelViewCount);

If you want the amount of all subviews in swift, you can just go with
self.subviews.count

Related

NSUInteger oddities with for loops [duplicate]

This question already has answers here:
NSUInteger in reversed loop confusion?
(2 answers)
Closed 6 years ago.
I use AppCode to tweak the code I've written in XCode. AppCode does awesome code inspections, and tells you where things can be improved.
One of the frequent inspections I come across points out that [SomeObjCFrameworkClass objectAtIndex] is expecting an NSUInteger which is in fact true...
- (ObjectType)objectAtIndex:(NSUInteger)index
however, I keep finding myself getting screwed by trying to follow this advice and change my ints to NSUIntegers.
For example, here's one piece of code that exploded when I did this change...
-(void)removeBadge
{
if ([[theButton subviews] count]>0)
{
NSUInteger initalValue = [[theButton subviews] count]-1;
//Get reference to the subview, and if it's a badge, remove it from it's parent (the button)
for (NSUInteger i=initalValue; i>=0; i--) {
if ([[[theButton subviews] objectAtIndex:i] isMemberOfClass:[MKNumberBadgeView class]])
{
[[[theButton subviews] objectAtIndex:i] removeFromSuperview];
[theButton setTitleColor:[UIColor lightTextColor] forState:UIControlStateNormal];
}
}
}
}
Any idea why this is happening.
There is a clue in the debug data pictured below, but I can't make sense of it.
NSUInteger in unsigned, so i>=0 condition in your for loop always evaluates to YES. After i reach 0, on next iteration you will get integer underflow, and i becomes NSUIntegerMax.
Updated: As far as I can tell from your code, there is no reason in processing subviews in reverse order. So, you can simply do
for (NSUInteger i=0; i<theButton.subviews.count; i++)
Otherwise, you can use something like
if (0 == i) {
break;
}
inside your loop or use do/while for example.

How to implement user interface containing four columns in ios with different content in each column?

I want to develop iphone application in which User Interface containing four columns with scrollable content vertically.
This simple idea can be implemented with UIcollectionview but i want to load different content in each column of collectionview with vertical scrolling for each.
So get me your views on the same how can I implement this?
Thanks,
Nirav Patadiya
1) Create a UICustomViewCell.
follow the link
http://adoptioncurve.net/archives/2012/09/a-simple-uicollectionview-tutorial/
set the flow layout as
[flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical];
You can't have independent scrolling of each column in a single UICollectionView (at least not while using flow layout).
You could try having four independent UICollectionViews within your view controller, side by side, each of which has a single item per row.
You can populate your collectionViewCells with different content. But
for this,I would recommend you to use PSTCollectionView. Here you can
check for the availability of UICollectionView. So,if you want
to develop an app for IOS5 and later,better idea would be PSTCollectionView.
Finally i have done this thing using four different scrollviews.
Adding content dynamic to each scrollview.
I use following code:
-(void)addContentToScrollView:(UIScrollView*)scrollview dataToScroll:(NSDictionary*)data
{
#try
{
int x=0;
int y=0;
int width = 80;
int height = 80;
int margin = 5;
UIColor *colorName;
if ([scrollview isEqual:scrollEvents])
{
colorName=[UIColor yellowColor];
}
else if([scrollview isEqual:scrollGroups])
{
colorName=[UIColor redColor];
}
else if([scrollview isEqual:scrollPlaces])
{
colorName=[UIColor greenColor];
}
else
{
colorName=[UIColor blueColor];
}
NSArray *arrTmp = [data valueForKey:#"call"];
for (int i=0; i<arrTmp.count; i++)
{
UIImageView *imgTemp = [[UIImageView alloc]initWithFrame:CGRectMake(x, y, width, height)];
[imgTemp setBackgroundColor:colorName];
[scrollview addSubview:imgTemp];
y+=imgTemp.frame.size.height+margin;
[imgTemp release];
}
scrollview.contentSize=CGSizeMake(scrollview.frame.size.width, y);
[colorName release];
}
#catch (NSException *exception)
{
}
#finally
{
}
This global method will be called as per your requirement you just need to pass scrollview which want to add data and dictionary with data to be added into scrollview.
I hope this code can help others to work.
Thanks

How to search for UIView inside many levels of UIViews?

Is there a better way to search for UIViews children inside 3-4+ levels of UIViews without using tag? Is there a much better way to go directly into the child UIView without having to traverse the tree every time? The tag is really not helping.
Thanks!
if you want to access a view directly you may use
[randomChildView.window.subviews objectAtIndex:0]
in order to avoid looping all subviews you can use of enumerateObjectsUsingBlock
- (NSArray*) allSubviews {
__block NSArray* allSubviews = [NSArray arrayWithObject:self];
[self.subviews enumerateObjectsUsingBlock:^( UIView* view, NSUInteger idx, BOOL*stop) {
allSubviews = [allSubviews arrayByAddingObjectsFromArray:[view allSubviews]];
}];
return allSubviews;
}
Hope it helps!

What are the first two subviews in a UIViewController?

I was dynamically creating buttons in Xcode 6 using Swift. I happened to noticed that there are already 2 subviews in UIViewController.view.subviews. I know that they are UIViews, but I haven't been able to figure out what specific subclass they are or what they do. Does anyone have any insight on this and is it ok to delete them?
If you try logging the class of these subviews :
for (int i = 0; i < self.view.subviews.count; i++) {
NSLog(#"%#", [self.view.subviews[i] class]);
}
You'll get :
Project[5175:589276] _UILayoutGuide
Project[5175:589276] _UILayoutGuide
You'll find more info on UILayoutGuides in this thread for example.

How to remove all subviews?

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.
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];
}
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.
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)
Try this way swift 2.0
view.subviews.forEach { $0.removeFromSuperview() }
view.subviews.forEach { $0.removeFromSuperview() }
Use the Following code to remove all subviews.
for (UIView *view in [self.view subviews])
{
[view 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];
}
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.
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--;
}

Resources