Handling UIDynamicBehaviors when removing the respective UIView - iphone

Periodically, I add a UIView to the UIDynamicAnimator, which has some behaviours of its own. But when I remove the UIView from it's superview (when it falls offscreen) the UIDynamicAnimator still keeps the UIView's behaviours in its 'behaviors' property.
My question is, exactly what is the best approach to handling the behaviours in a UIDynamicAnimator?
Do I have to manually keep track of all the behaviours pertaining to that UIView and manually remove them before removing the UIView from the view hierarchy?

[myBehavior removeItem:item] does not throw an exception if item is not part of myBehavior, so what you could do is have a generic removeView method that removes a view from all behaviors that could possibly pertain to it, something like:
- (void) removeView: (UIView *) view{
[_gravity removeItem: view];
[_collisions removeItem:view];
[_otherBehavior removeItem:view];
//and et cetra for all of your behaviors
[self.view removeItem: view];
}
Which could be called whenever you need to remove a view. Even if, say, the view is not part of _otherBehavior this method would still properly remove the view.

Related

simple uiview change not working

I am trying to just do a simple view change for proof of concept.
here is the code
- (void)swipedScreen
{
if (self.secondView.superview == nil) {
[myView removeFromSuperview];
[self.view insertSubview:secondView atIndex:0];
}
}
when I swipe the screen what happens is the view area just goes black... and becomes unresponsive.
I started with a navigatoin app, replaced the tableview with just a standard uiviewcontroller class.. that worked fine..Then i added a secondView (xib only) and changed its class to match the viewcontroller of the first view.
The reason I am finding this difficult is because i am trying to animate the views inside the navigation controller and not push a whole view onto the stack which I am used to doing.
I'll bet that blank unresponsive view is, in reality, your secondView object. I always test by setting [secondView setBackgroundColor:[UIColor greenColor]] and checking if the massive green rectangle actually shows up.
EDIT: having looked at your code, there are multiple problems that arose:
You never actually +alloc or -init anything.
You never actually touch those nibs or make a reference to them in code
You declare two UIView's as IBOutlets and Strong (two exact opposites, as IBOutlets are __weak, __unsafe_unretained, or assign), yet do not link them to anything.
I've taken the liberty of revising it (sans nibs). Take a look.
Did you init the secondView? if init,you can try to set frame for the secondView
Your inserting the view at the bottom of the stack,
[self.view insertSubview:secondView atIndex:0];
Try using addSubview instead. Also you need to set the views frame somewhere.

UIViewControllers... Memory Management With SubViews

I have UIViewController who has several subviews but tracking each and every subview allocated is difficult task as the actually coder is not me and need to handle the memory consumption.
My question is there a way to control the memory calling a recursive function to remove and release all the subViews in the UIViewController without knowing the actual reference name ?
As in the code below :
for (UIView* subview in view){
[subview removeFromSuperView];
[subview release] ;
subview = nil;
}
When you call removeFromSuperview on a view it will automatically decrement the retain count (because the superview no longer requires a reference to the view you've just removed).
If you have added your views to the superview in a standard manner there shouldn't be any need to do what you're doing - either you've added your views and then released them, or your views are properties and the release happens later.
The code you're proposing (the recursive loop on all subviews) is a bad idea, because you don't actually know whether your subview is safe to be released or not. You could easily trigger a bad access.

iOS SDK Check if view already exists

I have a UIWebView that is drawn programmatically and gets allocated and displayed through multiple subviews (the webview gets added to the superview).
This all works, however I have one little problem:
If 2 different subviews display this webview then I get 2 webviews, so when 1 view dismisses the webview the other remains. I don't want this.
Originally I was thinking just implement the webview in the superview class, however it didn't work.
How can I have the web view check to see if there are more then one of itself?
A webview instance can only be added to the view hierarchy once. If you have two webviews visible on screen at once, they are two different instances. You should keep track of these instances that you add to the hierarchy and when one dismisses, remove all the instances you are tracking from their superview.
You can also crawl a view hierarchy and look for instances of UIWebView.
for (UIView *subView in [myView subviews]) {
if ([subView isKindOfClass:[UIWebView class]]) {
[subView removeFromSuperview];
}
}
mhm, no, wait, it's not so clear what you are meaning...
You say: "...there are more then one of itself" and "...gets allocated and displayed through multiple subviews"
You probably mean that you have 2 instances of "the same" UIWebView class, but then you should not consider them as "the same object" which lives in 2 different superviews... they are different objects, everyone has its own properties...
Or did i misunderstood?
So, if you meant as i said and you just want to control from a subView (mhm... or we should say from its UIViewController) if there are other views which use a UIWebView.
I'd probably use one UIViewController "parent" where to load my subViews (eventually they could also have their own UIViewController, then every time i Alloc and addSubview a UIWebView in my subView i just add a tag to it:
myWebView.tag = 11;
it could change if needed for next one...
the purpose is to be able to control if in my UIView there are allocated some UIWebView,
now we can do that with this in my main parent UIViewController:
for (UIView *view_level_1 in [self.view subviews]) {
for (UIView *view_level_2 in [view_level_1 subviews]) {
if (view_level_1 >= 10) {
// do something: dismiss this UIWebView too...
}
}
}
it just control in all the subViews of the view of my mainViewControl if there is a subView "tagged" before (a tag is a sort of "name/id")
I'm not sure the structure of your subView could be like that, it was not so clear in your question, but you can change the code adopting it...
luca
Use UIView's isDescendantOfView method to know if any subView is currently present on parentView.
if([addedSubView isDescendantOfView:parentView])
{
//addedSubView is subview of parentView
//Take necessary action.
}
else
{
//addedSubView is not subview of parentView
//Take necessary action.
}

Calling setNeedsDisplay on a UIView from another class

I have a UIView subclass that I manipulate a lot of graphics on based on touches. All the [self setNeedsDisplay] calls seem to be fine.
However, I used an instance variable pointer to my same UIView subclass instance, and then tried manipulating it and then calling [UIViewSubClass setNeedsDisplay] from another UIView class, and DrawRect is never being called. Are there restrictions to where you can call setNeedsDisplay from?
(This method is called when a button is clicked on another UIView subclass. The method is being called, but not DrawRect)
-(IBAction)loadGrid2;
{
tempSoundArray = musicGridView1.soundArray;
[musicGridView1.soundArray setButtonArrayToNull];
[musicGridView1 setNeedsDisplay];
musicGridView1.soundArray = tempSoundArray;
NSLog(#"loadGrid2 was called");
}
drawRect: will only be called when it makes sense; ie, the view must be visible, onscreen, and dirty. Is your drawRect: ever called? It should be called when the view is first brought onscreen as well.
To add to Ben:
This most likely means that you have problems elsewhere. Your pointer may not be nil or otherwise invalid or the view may not be added to the hierarchy properly.
You may want to consider not handling this type behavior within the view and instead in the view controller. Control behavior and save presentation state in the view controller and don't subclass the view classes. It will simplify your code with less "pointer passing". This will also make it easier to debug this type of problem.
If you feel your view controller is getting bloated, consider splitting the responsibilities up among multiple view controllers.

how does one make a subview firstResponder

i am trying to get a subview to become firstResponder. my understanding is that this is done in its viewDidAppear method, like so:
- (void)viewDidAppear {
[self becomeFirstResponder];
}
while overriding canBecomeFirstResponder to return YES:
- (BOOL)canBecomeFirstResponder {
return YES;
}
however, when i insert the subview in its parent view's viewDidLoad method:
- (void)viewDidLoad {
subViewController = [[SubViewController alloc] init];
[self.view insertSubview: subViewController.view atIndex: 0];
[subViewController viewDidAppear: NO];
[super viewDidLoad];
}
(i call viewDidAppear manually, because it does not get triggered automatically), the subview does not become firstResponder.
why does the subview not become firstResponder? and how can i make it firstResponder?
thanks,
mbotta
btw, this is a rewrite of my original question:
i am trying to build an iphone app where a rootviewcontroller object manages two subviews, one of which should react to a user shaking his iphone.
after some digging, i concluded the subview must be made firstResponder in its view controller's viewDidAppear method. moreover, the canBecomeFirstResponder method should be modified to return YES.
so here's what happens: i instantiate the rootviewcontroller in the app delegate. in its viewDidLoad method, i tell it to addSubView firstViewController. all of this works just beautifully.
however, firstViewController does not react to any shaking. i sprinkled some NSLogs around and found that while we DO tell firstViewController in canBecomeFirstResponder to return YES, and while we DO tell it to [self becomeFirstResponder] in viewDidAppear, in actual fact, it is not the firstResponder.
so, my questions are:
1) does a subview actually need to be firstResponder in order to react to shaking?
a) if not, how does one make a subview react without being firstResponder?
2) how does one make a subview firstResponder?
what makes this interesting is that if i perform the same sequence (canBecomeFirstResponder, [self firstResponder], motionBegan:) in a different project with only one view controller, it all works flawlessly. clearly, i must be hitting a design flaw of my own making.
thanks,
mbotta
Not 100% sure, but this could be your problem. If we could see the offending methods it might be easier.
From the Event Handling Best Practices (emphasis added by me):
If you handle events in a subclass of
UIView, UIViewController, or (in rare
cases) UIResponder,
You should implement all of the event-handling methods (even if it is
a null implementation).
Do not call the superclass implementation of the methods.
If you call the superclass methods the events are probably getting passed along to the nextResponder.
EDIT
The Event Handling Best Practices link above is dead. I couldn't find that pull quote anywhere, but Event Handling Guide for UIKit Apps seems to be the most relevant.