Displaying UIViewController, NSOperationQueue - objective-c

I have been on an iOS 5 app in which I have an NSOperationQueue which works fine to get some data and create a UIViewController. However, at one point when every operation seems to be complete the app is unresponsive for quite a long time. Here's how it goes:
Get some data from DB
Queue - For each item Init a custom UIViewController object.
Hand each UIViewController object over to the MainViewController and display them.
Everything goes fine until the UIVC objects have to appear.
It goes past all the [[self view] addSubview:object.view]; and to the end of the function.
But then there is a huge lag, from 5 to 30 seconds before the NSLog statements inside the viewDidApear of the UIVC object show up...
So in code:
//MainViewController
-(void)displayNewView {
[[self view] addSubview:object.view];
NSLog(#"Done setup");
}
//-- Long unresponsiveness --//
//UIVC object
-(void)viewDidAppear:(BOOL)animated {
NSLog(#"Start appear");
[super viewDidAppear:animated];
}
What could be causing this? Am I missing something obvious?
Thanks for the help!

It seems like it was the complexity of each UIViewController that delayed the whole process.
To me they seem simple but I guess the iPhone doesn't like creating 10 views at a time with several buttons, labels and images.
Simplifying the nib and making sure only what is used is allocated and initialized helped a lot.. but its still not perfectly fluid.

Related

Reloading UICollectionView causing flickering

I have subclassed a CollectionView and using it using to display a collection of images in different categories. For example: Most Popular, Most Viewed. I access each category/page through a TabbarController.
The classes I have are:
Main class - MediaList - Base class for fetching and displaying media in a collection view depending on what type of media is requested.
SubClasses - MostPopular and MostViewed are both very light classes that inherit from the main class.
The problem is that when I move from MostPopular to MostViewed, the collection view initially displays the last category of pictures and then refreshes to the new...As a result you see a flicking effect.
Sample code from MediaList
- (void)viewDidLoad
{
[super viewDidLoad];
self.mediaCollection.dataSource = self;
self.mediaCollection.delegate = self;
[self getMedia];
}
(void) getMedia
{
NSLog(#"///////////////////////// GETTING MEDIA /////////////////////////");
XMLGenerator * sharedXmlGen = [XMLGenerator sharedXmlGenerator];
GlobalVars * sharedGlobalVars = [GlobalVars sharedGlobalVars];
sharedXmlGen.assetFlag = _contentFilter;
NSLog(#"The filter is: %#", _contentFilter);
[sharedXmlGen getPhotoVideoWithCallBackFunction:^{
[_mediaCollection performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
}];
}
Sample code from SubClass (MostPopular):
- (void)viewDidLoad
{
[super setContentFilter:FILTER_POPULAR]; //Set the filter for the type of content
[super viewDidLoad];
// Do any additional setup after loading the view.
}
Two clarifications:
I should add that I am trying to re-use as much code as possible without having to create new views on the storyboard or controllers.
Because the media returned is very dynamic and can be updated regularly, I have had to reload my data (using getMedia) on viewDidAppear. This now means each selection of a particular page will result in the flickering when the new view is loaded...
Updates
- After further investigation it looks like this has nothing to do with subclassing the uicollectionview. The issue instead is just reloading data into the uicollectionview. To be sure, I just clicked on one of the two subclassed views. I also added a reload method to the viewdidAppear method just to see the issue get even worse. It's also much easier to see that the issue is that last set of images in the collection view initially displays the last category of pictures before the new one refreshes. Then once the collection is refreshed I get the flicker.
*Updates Oct 4 *
Starting to think my best solution is to display a waiting indicator and block the page while loading. I did try setting the uicollectionview to nil, and believe that will solve the problem as well, but not sure it will be straightforward to reset.
Although it may not be immediately apparent in the code above the root cause was actually the getMedia call. All of the subclassing etc. works perfectly fine.
Specifically having the reload method in the getMedia call and was creating the issue.
[_mediaCollection performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];

icarousel not displaying items

I've been working with iCarousel for about a week now, and I've had great success with outside testing. Now, I'm trying to put it into my app and it won't display the views. I was using UIViews to be displayed originally, which was working fine in my test programs, but due to sheer frustration im going as basic as possible and have literally just copied everythinng over from the examples. I connected the delegate and datasource, I called reloadData, ive done everything i could possibly find to fix this and it's not getting fixed. here's some code implementing the actual icarousel:
- (IBAction)coverflowPressed:(id)sender {
self.carousel = [[iCarouselExampleViewController alloc]
initWithNibName:#"iCarouselExampleViewController" bundle:nil];
[self presentViewController:self.carousel animated:YES completion:nil];
}
The rest of the code is basically copied from an example that works outside my app. As i mentioned, i DID connect the delegate and dataSource. It displays the background just fine, but it's like the carousel is empty; it has no items in it, and yes, there ARE items in it. any ideas for me?
EDIT
Maybe i connected the delegate and datasource wrong. could somebody maybe explain how to do that from an app thats already halfway through production?
Breakpoints prove that it's never reaching carousel-specific functions, like viewForItemAtIndex or even awakeFromNib. viewDidLoad is called, so i set the delegate and datasource in there. Originally they were set in the nib but i changed it to programmatically. anyways heres my viewdidload method:
- (void)viewDidLoad {
[super viewDidLoad];
self.carousel.delegate = self;
self.carousel.dataSource = self;
//configure carousel
_carousel.type = iCarouselTypeCoverFlow2;
}
it reaches the end of this function but it never goes any farther with it...

UINavigationController stops pushing view

We use a navigation controller and a view controller to display a question to the user. Everything has been working fine but we made some UI adjustments so we can port the application to iPad, the only changes were to make the frame of the table view dynamic to be either on iphone or ipad. However now when we get to the 187 question out of 335 it doesn't push the new question anymore... it pushes a blank screen and the "viewDidLoad" method of the pushed view controller is never called, as it has been the past 187 times. We have setup break points to make sure the navigation controller and view controller are still be allocated in memory and they are.
Here is the viewDidLoad of the view controller that gets called every new push...
- (void)viewDidLoad {
_tableView = [[QuestionTableView alloc] initWithFrame:self.view.frame style:UITableViewStyleGrouped];
_tableView.center = CGPointMake(self.view.center.x, self.view.frame.size.height/2);
[_tableView setDataSource:self];
[_tableView setQuestionDelegate:self];
[_tableView setDelegate:self];
_tableView.scrollEnabled = YES;
[_tableView setBackgroundView:[[[UIView alloc] init] autorelease]];
_tableView.directionalLockEnabled = YES;
_tableView.delaysContentTouches = NO;
_tableView.backgroundColor = [UIColor clearColor];
_tableView.opaque = NO;
[self.view addSubview:_tableView];
}
We push the the view controller by...
[questionsNavigationController pushViewController:viewController animated:YES];
Thanks in advanced! :)
If you make the tableview smaller you can get through the entire set of 335 questions ? Are you creating a ViewController per question ?
You could run the project with instruments to check for a memory leak.
Do you really need all questions on the stack? How about a popViewControllerAnimated:NO before pushing the next one, also with animated:NO?
It works on the simulator because it's memory is the PC's memory. Put an NSLog into your -didReceiveMemoryWarning method to see it running out of memory.
Probably you shouldn't use NavigationController this way. It's.. ugly.
I would do one of the following:
"pop" ViewControllers that are 5-10 views behind (using setViewController). In other words - maintain 5-10 views behind, the others will be freed (and the result saved). Once the user decides to get back (and there are 3-4 views in the stack), reconstruct few more.
implement the NavigationController behaviour yourself - just replace the views instead of stacking them. Once the user gets back, reload the view with the needed data.
If you realy think that your implementation is ok - try to free as much possible memory from your view, once things get hot.

willAnimateRotationToInterfaceOrientation being called BEFORE viewWillAppear

I just tracked down a crash I was having in my iOS app and it is related to willAnimateRotationToInterfaceOrientation being called before viewWillAppear.
I have an app with two views. Basically, when view1 disappears, I release some arrays, assuming they will be re-initialized when it re-appears in viewWillAppear.
However, if I change orientation in view2 then switch back to view1, this causes willAnimateRotationToInterfaceOrientation to happen before view1 has calledviewWillAppear and re-initialized everything and this causes a crash.
Is there any way to delay willAnimateRotationToInterfaceOrientation until after the view has appeared and everything has been re-initialized?
If not, the only solutions I can see are either not using willAnimateRotationToInterfaceOrientation (which results in an ugly looking orientation change) or not releasing my data when I switch from view1 to view2 which results in more memory being used than necessary.
Does anybody have any thoughts on what I should do?
You can use lazy-loading style code avoid your problem, like:
NSArray* someData;
-(void)somefun1{
if (!someData) {
[self loadData];
}
//use your data
}
-(void)somefun2{
if (!someData) {
[self loadData];
}
//use your data
}
-(void)loadData{
//some loading code
}
use lazy-loading style code you never need mind event calling order.

Why strange crash with mapview happen?

I have a very simple app. 1 navigationController with 2 viewControllers.
The first view has only a button.
The second view has a map view (MKMapView).
I checked show currentlocation property of this map view
I created outlet and then connect everything by using Builder Interface.
In the dealloc method of the second one, I set nil to delegate of mapview, and then release mapview outlet.
mapView.delegate = nil;
[mapview release];
When I tap the button in view1, view2 will be loaded, and then I tap back button. If I do it normally, everything works well. But If I do it very quickly, repeat many times. The app will be crashed.
If I do not release mapView or I do not check showcurrentlocation property, app works well.
I can't figure out why this happen. Anyone helps me solve this problem. Thanks so much !
My fix in controller class was to ..
(void)dealloc
{
mapView.showUserLocation = NO; // Work around bug in MKMapView
[super dealloc];
}
Try launching your app via Instruments with Zombie instrument added. It should show you overreleased object. You'd also should add the Allocations instrument with VM tracker to see how memory consumption goes over time. This way you'd get your answer very quick.
p.s. more code would help better.