So I have a UIScrollView that is populated with a series of MyCustomViews that are subclasses of a standard UIView. In the delegate callback "scrollViewDidScroll I am trying to loop through all the subviews and call a specific function on them but I don't think the typecasting is working. Here is my code below:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
for(UIView *subView in [scrollView subviews){
MyCustomView *customView = (MyCustomView *)subView;
[customView myMethod];
}
}
When I call "myMethod" on customView, the program crashes saying an unrecognized selector was sent to instance. I believe that my type-casting is the issue as the method myMethod works in other situations. So how do I remedy this situation?
Solution 1:
If you do the following, you don't even need to cast your object to MyCustomView *. It can be of any type, e.g. UIView.
if([subView respondsToSelector:#selector(myMethod)]) {
[subView performSelector:#selector(myMethod)];
}
Solution 2:
You can check the object type before doing the cast.
if([subView isKindOfClass:[MyCustomView class]]) {
MyCustomView *customView = (MyCustomView *)subView;
[customView myMethod];
}
For "catch" this issue, use
if([customView respondsToSelector:#selector(myMethod)]){
[customView myMethod];
}
and with this, the app don't crash.
Also in your for use for(MyCustomView* customView in [scrollView subviews]){
Related
I am creating a UIView every time I click on the button, but the problem is all other views are not getting deleted.
It's increasing the memory of the application
You can set a tag for UIView objects.
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
view.tag = 2016;
[self addSubview:view];
Then, you can remove it later using this code :
UIView *view = [self viewWithTag:2016];
[view removeFromSuperview];
You can also keep a reference to an UIView object with a property.
#property (nonatomic, strong) UIView *view;
So you can remove it very easy.
Try this:
Assign a tag(may be 100) to the button.
NSArray *subviews = self.view.subviews;
for(UIView *subview in subviews) {
if(subview.tag != 100) {
[view removeFromSuperview];
}
}
-removeFromSuperview method release's memory after it is called only in case if your view is not retained by anything else
e.g.
Simply removing view from superview may not be sufficient to deallocate it can have view that has an outlet connection & declared property for it with retain or strong attribute, so in this case it will be retained by the controller while it is being loaded from nib file and you may need to release that view.
[yourView removeFromSuperview];
self.yourView = nil;
I have a bunch of UIViews that I subclassed that I have been adding to self.view e.g.:
MySpecialView *myView = [[MySpecialView alloc] init];
[self.view addSubview:myView];
Now I want to remove them all from self.view but only those custom ones. I don't want to remove any of the others (I have some other views with options in them etc). Is there anyway of doing this at all? Can I loop through all the subviews and check their type? Any pointers on this would be great! Thanks!
Try a loop like this
for (UIView *view in self.view.subviews)
{
if ([view isKindOfClass:[MySpecialView class]])
[view removeFromSuperview];
}
This simply iterates through all of the subviews and removes any that are of class MySpecialView.
Swift way
for subview in self.view.subviews {
if subview.isKindOfClass(MyClass) {
// Is that class!
} else if subview.isMemberOfClass(MyClass) {
// Is that class or a subclass of that class!
}
}
I have a category for UIView which contains this method to remove all of its subviews:
- (void)empty {
for (UIView *subview in self.subviews) {
[subview removeFromSuperview];
}
}
and upon profiling my project I see multiple memory leaks all pointing to this code:
[wrapperView empty];
which in turn calls the first method.
I searched on Google and found out a cleaner and better solution using:
[self.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
which doesn't create memory leaks.
My question is, why is the old solution creating memory leaks? Aren't the UIView *subviews released at the end of the for loop?
In the first method you are mutating the array while iterating through it, in the second you are just sending a message to each object in the array.
To see this for yourself, replace the first method with
NSArray *subviews = self.subviews.copy;
for (UIView *view in subviews) {
[view removeFromSuperview];
}
This way you are working on a copy of the subviews array.
I'm trying to bringtofront my subview because the delete button keeps disappearing.
#implementation MyCell : UITableViewCell
- (void)layoutSubviews
{
[super layoutSubviews];
for (UIView *subview in self.subviews) {
for (UIView *subview2 in subview.subviews) {
NSLog(#"HERE!");
if ([NSStringFromClass([subview2 class]) isEqualToString:#"UITableViewCellDeleteConfirmationView"]) {
NSLog(#"got inside the if!");
[subview2 sendSubviewToBack:subview];
[subview bringSubviewToFront:subview2];
[self.superview bringSubviewToFront:subview2];
}
}
}
}
#end
I subclassed UITableViewCell. Both the NSLogs are printing so I know it's getting in there, but I've tried all 3 of these methods to put the view in front. Any ideas why this wouldn't be working?
subview2 is a subview of subview, which is a subview of self. The receiver of the sendSubviewToBack: or bringSubviewToFront: message must be the superview of the view given as argument. Therefore only the second one of the calls you make is valid. The correct calls would be
[self.superview bringSubviewToFront:self];
[self bringSubviewToFront:subview];
[subview bringSubviewToFront:subview2];
(And the same for sendSubviewToBack:.)
As for your actual problem, I can't figure out the view hierarchy you are using from the code posted, but it seems that it is incorrect. You should probably not have your custom views as direct subviews of self, but rather as subviews of self.contentView (as per Apple's documentation).
In my app I need to call some UIViews more than once. But in one of my method, i've a code like :
[self addSubview:UIImageView];
But i've read that addsubview method must be call once. So, to let the code how is it, how could I check if it's already on subview ? Like :
if ([UIImageView isOnSubview] == NO)
{
[self addSubview:UIImageView];
}
Because I don't find any method to check this :/
Thank you !
You are probably looking for UIView's -(BOOL)isDescendantOfView:(UIView *)view; taken in UIView class reference.
use this one
for (UIView *subview in [self subviews])
{
NSLog(#"%#", subview);
// ---------- remember one thing there should be one imageview ------
if(![subview isKindOfClass:[UIImageView class]])
{
[self addSubview:UIImageView];
}
}