Scrolling exits CFRunLoopRun on iPhone - iphone

I've created a UIView, and I'm showing it as modal dialog by using CFRunLoopRun.
Everything works fine, but when the user does any kind of scrolling in the UIView, it exits the CFRunLoopRun.
I've read about this issue but didn't find a solution.
Any idea?
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
[customdialog show]; // my method to show the dialog
CFRunLoopRun(); //exits CFRunLoopRun when scrolling on customdialog (UIView)
[pool release];

Scrolling causes the runloop mode to change, and this is probably causing CFRunLoopRun() to terminate. So you'd need to keep re-running CFRunLoopRun() repeatedly until you set some flag to stop.
But there's seldom any reason to do this. You can subclass UIAlertView, or you can simply make your dialog full-screen so that it prevents touches on the other view (that's how I always do this). Just create a transparent, full-screen view, and put your dialog in it, and add it as a subview of the current view. Then there's no special futzing with the runloop.

Related

Why releasing an UIAlertView just afer showing it whereas it is not a blocking method?

I have been studying how to display a modal view with UIAlertView for a few hours and I understood that showing it does not "block" the code (the modal window is displayed and the program keeps running - we must use delegate to catch the selected actions on this modal window). Then I studied several examples and noticed that every example always release the modal window just after showing it. How can this work properly since the view will be released instantly as the code does not stop ?
Here is the example (there are many others on Google):
[[UIAlertView alloc] initWithTitle:#"Title" message:#"Message..." delegate:NULL cancelButtonTitle:#"OK" otherButtonTitles:NULL];
[alert showModal];
[alert release];
Thanks for your help,
Apple 92
I'm not sure where you're getting -showModal from (the usual method is just -show), but that act adds the alert to the view hierarchy. When a view is added as a subview of another view (I believe in this case it's a system-level view that is being added to) it's retained automatically, so you don't have to.
The alloc method will return you an instance that has a retain count of 1.
The showModal method probably retains the alert view so it remains on screen (and retained) until a button is tapped. It makes sense to me, since you are presenting it as a modal window, so it doesn't have a "parent", that is responsible of releasing it.

crash when switching between tableviews using tab controller and MBProgressHUD

I have two tableviews. One loads when I select one tab, and the other loads when I select the other tab.
I use MBProgressHUD to allow for quick switching between the tabs as I pull the tableview datasource from the web using Objective Resource and that can take a little bit. So I throw up a HUD progress indicator waiting for the data to load.
This in turn has allowed me to quickly switch between tabs. But.... If I do it quick enough an exception occurs
EXC BAD ACCESS
with NSZombiesEnabled I get this:
2010-08-02 22:44:43.116 Film Fest[962:8703] *** -[MBProgressHUD release]: message sent to deallocated instance 0x85490b0
In both my tableviews I use two different custom tableviewcells.
What should be my next step to debug this?
... so I have moved the code to create the HUD from my viewWillAppear: method to viewDidLoad: and the crash went away.
// The hud will dispable all input on the view (use the higest view possible in the view hierarchy)
HUD = [[MBProgressHUD alloc] initWithView:self.view];
//HUD.graceTime = 0.5;
//HUD.minShowTime = 5.0;
// Add HUD to screen
[self.view addSubview:HUD];
// Register for HUD callbacks so we can remove it from the window at the right time
HUD.delegate = self;
// Show the HUD while the provided method executes in a new thread
[HUD showWhileExecuting:#selector(loadFilms) onTarget:self withObject:nil animated:YES];
however this doesn't really fix my issue as viewDidLoad only occurs once in a long while especially with the new multitasking. I need this HUD to fire the selector everytime the tableview appears.
Why is it not correct for me to have it occur in the viewWillAppear... is it because that can be loaded so much and I just kept on allocating the object? perhasp I should allocate in viewDidload and fire the
// Show the HUD while the provided method executes in a new thread
[HUD showWhileExecuting:#selector(loadFilms) onTarget:self withObject:nil animated:YES];
only in my viewWillAppear:?
Thoughts?
Find all the places where you init/retain/release/autorelease an instance of MBProgressHUD.
The NSZombie tells that this project receives a release message after it is being already deallocated (retain count is zero).
It will help if you will post some code - otherwise it is too difficult to help you...
EDIT:
As you have mentioned in your edit, it would be much better if you'd initiate the HUD only once per view controller (e.g. in viewDidLoad) and call to showWhileExecuting each time you need it (e.g. in viewWillAppear).
But it still doesn't explain the crash.
You you execute the entire code you have posted (as is) for a few times from the same instance of a view controller then you should have memory leaks. That is because I don't see where you release the old instance of HUD.
In addition, you are better set the delegate of the HUD to be nil right before releasing it and before calling the [super dealloc]; in the dealloc method of the view controller.
The last one might cause the EXC BAD ACCESS error.
One more thing, if the entire code you have posted is executed more than once then you should also have few HUD views under the self.view.
I don't know what HUD does in the background - maybe this causes the error...

iPhone: UIAlert dialog Appears 3 Times for Every Call

I have a UIAlert that pops up 3 times every time it is called. It appears and then disappears before I can click on it. Could it be that the viewDidLoad itself is being called 3 times?
I implemented an UIAlert in the viewDidLoad of my app:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:alertMessage delegate:self cancelButtonTitle:ok otherButtonTitles:nil];
This is the viewDidLoad in the rootViewController, that manages the views:
- (void)viewDidLoad {
Kundenkarte *kartenAnsicht = [[Kundenkarte alloc]
initWithNibName:#"Kundenkarte" bundle:nil];
kartenAnsicht.rootViewController = self;
kartenAnsicht.viewDidLoad;
self.map = kartenAnsicht;
[self.view addSubview:kartenAnsicht.view];
[kartenAnsicht release];
// [super viewDidLoad];
}
The viewDidLoad that evokes the UIAlert is in the kartenAnsicht view controller.
I hope someone can help me because I'm out of ideas.
You don't need to call -viewDidLoad yourself, it's run automatically by the NIB-loading mechanism. That means you get extra invocations of -viewDidLoad: one by design, and extras whenever you call it.
First of all, you should never put any type of display in viewDidLoad. That method is intended for behind the scenes configuration after the view is first read from nib. There is no certainty that it will be called every time the view displays because after the first time it loads, the view maybe held in memory and not reloaded from nib.
Instead, put the call to evoke the NSAlert in viewWillDisplay or viewDidDisplay. This will display the alert each time the view appears.
I doubt that viewDidLoad is called three times but to check for that just put an NSLog in the method to see how many times it is called.
When you say that:
i implemented an NSAlert in the
viewDidLoad() of my app:
... what does that mean? What object exactly has the method? If it is the application delegate, this will not work because the application delegate protocol does not respond to viewDidLoad. It has to be in a UIViewController.
Edit01:
See this post that had the same problem: UIAlertView Pops Up Three Times per Call Instead of Just Once
Short answer: You kill the alert by releasing it. Either retain it as a property of the view controller or better yet, display the alert with runModal instead of show and capture the button number returned immediately.
It would be helpful to see the code around the alert call.
I am using an alert whenever the reachability changes. Since reachability is checked repeatedly, the alert could get called repeatedly. To alleviate that, I wrap the alert code like so:
if (!myAlert) { /* set up and show myAlert */ }
However, one problem with this is that when you click the Cancel button, the alert will remain non-nil, and therefore can never show again because of that conditional. If someone could add to this response with a fix for that, that would be great. I assume I can add a handler for the cancel button that will destroy myAlert.

How can I populate a UIViewController after it's loaded?

I'd like my UIViewController to appear on the screen with a "Loading..." UILabel in the center and then, once that's been displayed, start loading data to display.
How can I achieve this? I tried loading it in viewDidAppear:, but at this point the view has still not been displayed on the screen, so the app appears unresponsive to users. If I try setting a short timer (0.0001 seconds) so that the view will be displayed and then the data loading method gets called in the run loop after that, for some reason the time it takes from opening the view controller to seeing content is about three times as long as it was without the timer. In this case, the Loading... text appears, but the user has to wait way too long.
What's the best way to do this?
if I have not misunderstand your purpose, I think that you just want sow a 'loading' status to user, right ? if so , I suggest that you may use a simple ViewController to show the label 'Loading...' and then create the MainViw or next view which you want show to user in the end, when it was done, hide the first view show the MainView on screen...
Better do this in a thread from viewDidLoad and call your method in a thread, before calling the thread show your label and when the data is loaded through the thread hide the label.
you can do it like this.
-(void)viewDidLoad{
[self showLabel];
[NSThread detachNewThreadSelector:#selector(loadData:) toTarget:self withObject:nil];
}
Update
- (void) loadData:(id)object{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//Network Operations
//...
//...
//...
//...
[self performSelectorOnMainThread:#selector(reloadView:) withObject:arg waitUntilDone:[NSThread isMainThread]];
[pool release];
}
Hope this helps.
Thanks,
Madhup

How do I create a reusable Loading Screen?

How do I create a loading screen that can be reused at any given time. I'm aware of the Default.png but I need the flexibility to plug in a loading screen at any point during the application life cycle.
This is what I have thus far.
//inside a method that gets called by a UIButton
LoadingViewController* loadController = [[LoadingViewController alloc] initWithNibName:#"Loading" bundle:nil vertical:NO];
[self.view addSubview: loadController.view];
//some method call that takes a few seconds to execute
[self doSomething];
//This loads some other view, my final view
[self.view addSubview: someOtherView]
but it seems that the loading view is never displayed. Instead the previous view stays there until the "someOtherView" gets added. I put trace logs and the code does seem to get executed, I even replaced [self doSomething] with a sleep(2), but the intermediate loading view is never displayed.
If I remove [self.view addSubview:someOtherView]; then after a few seconds...(after doSomething finishes executing) the load view is displayed since there is no view that is pushed on top of it, however this is obviously not the functionality I want.
Can explain this behavior? Is there something about the rendering cycle that I am misunderstanding because it doesn't seem like the view (on the screen at least) is instantly updated, even though I call a [self.view addSubview: loadController.view];
Would I need to create a separate thread?
In general, for changes in the UI to be made visible to the user, control must return to the main runLoop. You are only returning to the runLoop after taking the loading view down and replacing it with the other view. One strategy for dealing with this is to move the code that does the loading onto another thread. NSOperation and NSOperationQueue can be used for this.
An even simpler approach is to use performSelectorInBackground:withObject to do the processing. Once processing is complete the UI can be updated again to show the data. It is important to remember that the UI updates must be carried out on the main thread. Use performSelectorOnMainThread:withObject:waitUntilDone: to accomplish this from the loading thread.
This sounds like a lot of complication but it is really as simple as breaking your single method up into three separate methods as follows:
Display the loading view and start the background process - this is the button action method.
Do the background loading - called from the button action function with performSelectorInBackground:withObject.
Remove the loading view and update the display with the data - called from the background thread with performSelectorOnMainThread:withObject:waitUntilDone.
I created a subclass of UIView where I initialized how my loading-view should work and look like. (My view appeared and slided in from the bottom with an nice animation).
I then added code that handled whether the loading-view should be visible or not in a subclass of UIViewController.
I then let all my viewcontrollers be an subclass of my new viewcontrollerclass which made it possible for me to do:
[self showloadingMessage:#"loading..."];
in all my viewcontrollers...