addSubview: method horribly slow - objective-c

I am trying to initialize a ViewController from another. Here is the code written in my first ViewController:
MediasViewController.h
#import "MediasVideosViewController.h"
#interface MediasViewController : UIViewController <UIWebViewDelegate>
{
NSArray* videosList;
MediasVideosViewController *mediasVideosViewController;
}
#property (nonatomic, retain) NSArray* videosList;
#property (nonatomic, retain) MediasVideosViewController* mediasVideosViewController;
MediasViewController.m :
if (self.mediasVideosViewController == nil)
{
MediasVideosViewController* mediasVideos = [[MediasVideosViewController alloc] initWithNibName:#"MediasVideosView" bundle:nil];
self.mediasVideosViewController = mediasVideos;
self.mediasVideosViewController.videosList = self.videosList;
[mediasVideos release];
}
NSDate *start = [NSDate date];
[mediasVideosViewController.view addSubview:nil];
NSLog(#"adding nil to mediasVideosViewController.view took %f seconds", [[NSDate date] timeIntervalSinceDate:start]);
Console result :
adding nil to
mediasVideosViewController.view took
4.261444 seconds
Seriously? More than 4s to add nil to mediasVideosController ? It's swings between 1s and 5s.
But if I remove this line :
self.mediasVideosViewController.videosList = self.videosList;
from MediasViewController.m, I get a really shorter loading time, like :
adding nil to
mediasVideosViewController.view took
0.007613 seconds
It drives me crazy...
Does anyone have a solution?

When you call mediasVideosViewController.view, you are basically calling loadView for the first time. You aren't just adding a subview, you are creating the entire view with that call.
Presumably, when you set the list of videos you are giving your loadView method a lot more work to do. This will result in the behavior you see.
In a nutshell, check out your loadView method for clues.
EDIT: I noticed you were loading the view controller from a NIB file, in that case you want to check viewDidLoad.

Related

Label update is null

I'm having an issue with a label not updating correctly in my UI. I have an Mac OS X app which uses a outline view to switch views. I want to simply have the date displayed to the user in a label on the view which is switched to (FirstViewController). When implemented alone in a new project I have no issue. But when implemented where the view changes, the value of the label does not update, in fact the console output indicates that _dateLabel is (null) even after being set prior. Any suggestions? I must be missing something quite fundamental!
Console output:
2014-08-30 19:54:22.719 OutlineView[10420:1613022] StringedText is 30 August 2014
2014-08-30 19:54:22.720 OutlineView[10420:1613022] label value is (null)
I include the following code:
//
// FirstViewContorller.h
// OutlineView
#import <Cocoa/Cocoa.h>
#interface FirstViewContorller : NSViewController
#property (weak) IBOutlet NSTextField *dateLabel;
-(void)updateDateScreen;
#end
//
// FirstViewContorller.m
// OutlineView
#import "FirstViewContorller.h"
#implementation FirstViewContorller
#synthesize dateLabel = _dateLabel;
-(void)updateDateScreen{
//date calculation for main window
NSDate *now = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterLongStyle];
NSString *stringedText = [formatter stringFromDate:now];
_dateLabel.stringValue = stringedText;
NSLog(#"StringedText is %#", stringedText);
NSLog(#"label value is %#", _dateLabel.value);
}
#end
//
// AppDelegate.m
// OutlineView
#import "AppDelegate.h"
#import "Book.h"
#import "FirstViewContorller.h"
#interface AppDelegate()
#property (weak) IBOutlet NSOutlineView *outlineView;
#property (weak) IBOutlet NSTreeController *booksController;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
//other code here
//Call the update method in FirstViewController to load date label
FirstViewContorller *instance = [[FirstViewContorller alloc]init];
[instance updateDateScreen];
}
//further unrelated code
#end
You have:
NSLog(#"label value is %#", _dateLabel.value);
And because it is outputting "null" you think that your value is "null" when in all likelihood it is _dateLabel that is null.
You are creating the instance object, but then calling a method that updates a UI object, which may not have been unarchived from the xib file by the time you are calling it. So although your date formatter is correctly creating a string, it is trying to set it on a nil object.
You can see this for yourself by examining the output of of:
NSLog(#"label is %#", _dateLabel);
which will probably return a "null" as well.

Possible Memory Leak in Objective-C?

Just starting out with Objective-C after spending years in Python.. still trying to wrap my head around some concepts.. I can't seem to figure this out but every time I either increment up or deduct from myCount it retains the older variable in memory. I am using ARC so shouldn't it autorelease? I have a feeling it has to do with self.varOfMyCount = [NSString stringWithFormat:#"%d", myCount];
Header:
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate>
{
IBOutlet NSMenu *statusMenu;
NSStatusItem *statusItem;
}
- (IBAction)itemOne:(id)sender;
- (IBAction)itemTwo:(id)sender;
- (IBAction)itemThree:(id)sender;
#property (assign) IBOutlet NSWindow *window;
#property (nonatomic, copy) NSString *varOfMyCount;
#end
int myCount = 0;
Implementation:
#import "AppDelegate.h"
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength ];
[statusItem setMenu:statusMenu];
[statusItem setTitle:#"Status"];
[statusItem setHighlightMode:YES];
}
- (IBAction)itemOne:(id)sender {
myCount++;
self.varOfMyCount = [NSString stringWithFormat:#"%d", myCount];
NSLog(#"%#",self.varOfMyCount);
[statusItem setTitle:self.varOfMyCount];
}
- (IBAction)itemTwo:(id)sender {
myCount = myCount-1;
self.varOfMyCount = [NSString stringWithFormat:#"%d", myCount];
NSLog(#"%#",self.varOfMyCount);
[statusItem setTitle:self.varOfMyCount];
}
- (IBAction)itemThree:(id)sender {
NSLog(#"Quit.");
[[NSApplication sharedApplication] terminate:nil];
}
#end
From your images, it doesn't really look like there is a problem. In order for your app to run it does need to use memory. Depending on what you do it will use different amounts.
Using [NSString stringWithFormat:#"%d", myCount]; requires more than you might think because you are asking the system to parse your format string and inject parameters into it. Parsing and scanning a string isn't a trivial operation.
In a number of cases when memory is allocated for a task it isn't released. This is usually the case when it's expensive to create (like the scanning structure, or parts of it) or is likely to be used repeatedly.
You should be worried if the memory grows bigger each time you do the same activity and return to your 'transient' state. Consider running multiple iterations of your button push and, between each push, take a heap shot. If each heap shot (apart from the first and last) are empty (or very close to it) then everything's good. If not, it will show exactly what isn't being released.

self.view removeFromSuperview crashes

i hope this is my last question for a while, I open a xib file via:
Results1 *myView1 = [[Results1 alloc]initWithNibName:#"Results1" bundle:nil];
[self.view addSubview:myView1.view];
I have a button on the second xib file:
-(IBAction)Button1:(id)sender
{
[self.view removeFromSuperview];
}
It crashes every time:
0xecf09b: movl 8(%edx), %edi
I have the views linked
I am not sure if this is the problem:
#interface TestTypingToolViewController ()
{
NSString *iResults1;
NSString *iResults2;
NSString *iResults3;
NSString *iResults4;
NSString *iResults5;
NSString *Segment;
NSDictionary *ResultsData;
}
#end
Thanks for all your help, everyone!
The problem is I needed to turn off Automatic Reference Counting and everything worked.
It seems that you have got some issue with zombies, i.e., some object that is deallocated at some point but you try to access through some (dangling) reference. You could get more info about it by enabling zombies detection.
Actually, my guess is that you could fix this by storing Results1 *myView1 in a property of your class. Indeed, in your code, what happens is the myView1.view is retained by self.view; while myView1 is stored in a local variable, so the object (under ARC) should be deallocated when the variable is not used anymore. You have a mismatch here between the lifetimes of the two objects and this could lead to the crash.
ClassName.h
#property (nonatomic, strong) UIViewController *myView1;
ClassName.m
#synthersize myView1;
// in -(void)viewDidLoad
self.myView1 = [[Result1 alloc] init];
[self.view addSubview:self.myView1.view];

Objective-C - C style string allocation leak?

I have a very simple app. From the main screen I launch a new view ("learn view") that displays an image and a label. on the learn view there is a menu button and a next button. When the user taps the next button, the view updates the image and the label from char * array of C strings. However, when I do this, the instruments allocations shows a forever growing number of allocations that are not reduced when the view is destroyed by clicking the menu button. If I just display the learn view then click menu there is no problem, the allocations go up and then go back down to the prior level, but if I click next updating the label.text, then allocations are made that are not recovered. Instruments reports no leaks. here are relevant code snippets:
LearnVC.h
#interface LearnVC : UIViewController {
IBOutlet UIImageView *imageView;
IBOutlet UILabel *labelView1;
NSInteger page;
}
#property (retain, nonatomic) UIImageView *imageView;
#property (retain, nonatomic) UILabel *labelView1;
#property NSInteger page;
- (IBAction)handleNext;
- (IBAction) gotoMenu;
#end
LearnVC.m
#import ...
char *states[] { "Alabama", "Alaska", "Arizona", ... };
#define maxStates 50
#implementation LearnVC
#synthesize ...
- (void)viewDidLoad
{
NSString *tstring;
self.page = 0;
//test!!!!
tstring = [[NSString alloc] initWithCString:states[self.page] encoding:NSUTF8StringEncoding];
labelView1.text = tstring;
[tstring release];
[super viewDidLoad];
}
- (IBAction) handleNext {
NSString *tstring;
self.page++;
if (self.page > maxStates-1) {
self.page = 0;
}
//test!!!!
tstring = [[NSString alloc] initWithCString:states[self.page] encoding:NSUTF8StringEncoding];
labelView1.text = tstring;
[tstring release];
}
- (void)dealloc
{
[imageView release];
[labelView1 release];
[super dealloc];
}
This seems to occur anytime I update a view without removing (deallocating) it and re-adding it. Is there something with old C arrays that don't copy/release properly. Or some issue with UILabel.text properties that don't release memory? Any help is appreciated.
Thanks beforehand, Neal
I converted it to use NSArray -
I added this to the .h file
NSArray *statesArray;
and
#property (retain, nonatomic) NSArray *statesArray;
then in the .m file
in viewDidLoad
NSArray *objects = [NSArray arrayWithObjects:#"Alabama", #"Montgomery",
#"Alaska", #"Juneau" ,..., nil];
self.statesArray = objects;
//I assume that since I didn't init it, I don't need to release objects.
labelView1.text = [self.statesArray objectAtIndex:self.page];in dealloc
[statesArray release];
Then in my handleNext
labelView1.text = [self.statesArray objectAtIndex:self.page];
I run through the entire array, exit, reload, ect. and the allocations climb the first time through but stop climbing after I've been through the list once. This was not the case with the char * array, there must be something else going on, oh well, I'll just have to shed my old C ways and stick to NS/UI classes.
This seems to have solved it. Now I'll work on the image loads and see if the it works the same.
The initWithCString:encoding: method may make an internal copy of the C string you pass in, but is not guaranteed to free the copy during deallocation. Since the C strings you're passing are constant, and therefore can never be freed, you can instead use initWithBytesNoCopy:length:encoding:freeWhenDone: to avoid creating the extra copies. For example:
NSString *s = [[NSString alloc] initWithBytesNoCopy:someCString
length:strlen(someCString)
encoding:NSUTF8StringEncoding
freeWhenDone:NO];
Also, the system does a lot of caching, it acts like each control may cache the text it has used. I found that if I ran through the series a couple of times, then then allocations stopped rising, as if it had cached all it was going to. Allocations did not go down to the starting point when exiting learn view, but subsequent runs did not add anymore.

EXC_BAD_ACCESS iPhone Dev

I am very new to development in Objective C but have a lot of experience in object orientated development in c# ASP. I've been trying to make a simple iPhone app where a PickerView control is accessing a data source.
In my header file (InstaTwitViewController.h) I have declared the following:
#interface InstaTwitViewController : UIViewController
<UIPickerViewDataSource, UIPickerViewDelegate> {
NSArray* activities;
NSArray* feelings;
}
I now try to inititialise my arrays in the viewDidLoad functions in my InstaTwitViewController.m file:
activities = [[NSArray alloc] initWithObjects:#"sleeping", #"eating", #"thinking", nil];
feelings = [[NSArray alloc] initWithObjects:#"psyched", #"sad", #"happy", nil];
but when I run the code on the simulator I get a Thread 1: Program recieved signal "ESC_BAD_ACCESS" error on the first line of code (where I allocate data to the activities array).
I put a break point on the line and it recognises it as an NSArray called activities but says "Invalid Summary" at the end.
Does anyone know why I am getting this error? I have looked at many threads about the ESC_BAD_ACCESS error but none have seemed to have helped me.
.h
#interface InstaTwitViewController : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate> {
NSArray* activities;
NSArray* feelings;
}
#property (nonatomic, retain) NSArray* activities;
#property (nonatomic, retain) NSArray* feelings;
#end
.m
#import "your.h"
#implementation InstaTwitViewController
#synthesize activities, feelings;
- (void)viewDidLoad {
[super viewDidLoad];
[self.activities addObject ~ /* Do your code here */];
}
#end
Becareful you should stay on self.~ if you don't want to lose your value.
By the way, I am Korean~ ^^;