What are the first two subviews in a UIViewController? - ios

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.

Related

Is there any simple way to change UIPageViewControllerNavigationOrientationHorizontal scroll animation

I want the UIPageViewControllerNavigationOrientationHorizontal to scroll from the left instead of the right (the opposite way of the default) in a page view controller.
Can anyone help?
I've been in this situation before and couldn't figure it out using the UIPageViewController. I'm not sure what your intent on your project is but this might help.
Use a UIScrollView and place the amount of UIView's you need inside. At the point you could just create a CGPoint and set your UIScrollView's content offset to your CGPoint. This way you would start at the last page(view) and can scroll to the left instead of the right. Something like this below. You can perform this in your viewDidLoad method.
CGPoint nameYourPoint = CGPointMake(640.0,568,0);
self.yourScrollViewName.contentOffset = nameYourPoint;
I was able to figure it out fairly simply:
When adding objects into the array of images, I added them in backwards like so:
for (int i = 1; i <= 81; i++) {
NSString *imageName = [NSString stringWithFormat:#"image%i.gif", i];
[self.mArray insertObject:[UIImage imageNamed:imageName] atIndex:0];
After that, in the root view controllers viewDidLoad method, I simply started the images at the end of the array
ModelController *objModelController = [ModelController new];
DataViewController *startingViewController = [self.modelController viewControllerAtIndex:[objModelController.mArray count]-1 storyboard:self.storyboard];
note:for some reason the length wasnt working, so I had to just add 2 empty objects to the beginning of the array and use
[objModelController.mArray count]-1
Hope this helps everyone out!

How to find number of subviews?

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

how can i differentiate and refer to various UITextViews that are created programmatically?

A UITextView is created each time i click on ADD button. Y-axis value is altered(say, y+=100) every time i click ADD and so a set of UITextViews are created one below the other. I cant figure out how to differentiate and access a particular UITextView. Thanks for any help!
EDIT:
-(IBAction)access:(id)sender
{
int tg=[sender superview].tag;
UIView *view=(UIView *)[textView viewWithTag:tg-1];
}
tg-1 because im trying to access the previous UITextView and when i do this it returns NULL.
Store them on a NSMutableArray:
NSMutableArray * views = [[NSMutableArray alloc] init]
Your IBAction
-(IBAction)access:(id)sender{
int tg=[sender superview].tag;
UIView *view=(UIView *)[textView viewWithTag:tg-1];
[views addObject: views];
}
Then you can get all the references with a integer index with:
UIView * storedView = [views objectAtIndex: 1];
Use a view tag to differentiate the views and access them.
You don't say how you're creating the new views, but something like this should work:
UIView* new_view = [UITextView initWithFrame(...)];
new_view.tag = generate_tag()
Where the generate_tag() function generates whatever naming scheme makes sense for your application.

Loop in a variable of type IBOutlet

I have twelve text fields as you can see below:
IBOutlet UITextField *ce_1;
IBOutlet UITextField *ce_2;
IBOutlet UITextField *ce_3;
....
IBOutlet UITextField *ce_12;
All I have to do is to set an existing object in an array in each of the variables that are responsible for the text fields, I'm currently doing as follows:
ce_1.text = myArray[1];
ce_2.text = myArray[2];
ce_3.text = myArray[3];
....
ce_12.text = myArray[12];
Not to be writing a lot, I thought I'd put this in an automated way within a loop as follows:
for(i=1;i<13;i++){
ce_[i].text = myArray[i];
}
But this command does not work the way I expected, so I would like your help to try to solve my idea and put it into practice, is there any way of doing this?
Research and start using IBOutletCollection. It will give you an array of text fields that you can build in your storyboard XIB.
Note that you may need to consider the order of the array, and that you might want to sort it (possibly based on the tag of each view).
Technically, you could use string formats and KVC to do what you're currently trying to but it is far from ideal.
You can't just replace ce_1 ce_2 ce_3 with ce_[i] it doesn't work that way. You can only use [number] with an nsarray variable (or decendents).
for example:
NSArray* myArray = #[#1];
NSLog(#"%#", myArray[0]);
You might want to look into IBOutletCollection in order to achieve something similar to what you're looking for.
However, contrary to other answers here IBOutletCollection are ordered by how you link them in the interface builder.
Refer to this for IBOutletCollections: How can I use IBOutletCollection to connect multiple UIImageViews to the same outlet?
You can use IBOutletCollection. You can also use key-value coding:
for(NSUInteger i = 0; i < 13; i++)
{
[[self valueForKey:[NSString stringWithFormat:#"ce_%u", i]] setText: myArray[i]];
}
This will give you what you want.
The way I like to handle these situations is creating a temporary array containing all the text fields:
NSArray *allFields = #[_ce_1, _ce_2, _ce_3, ...];
NSInteger i = 0;
for (UITextField *tf in allFields)
{
tf.text = myArray[i];
i++
}
IBOutletCollection also work but sometimes it gets hard to figure out when you come back to your project which label is #3 or #5 and such... I find this works better for me usually :)

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