Where to init MutableArray? - objective-c

I've tried to init/alloc it in initWithFrame but then objects wouldn't get added.
It'd only work in this method I'm calling but I call this method each time user refreshes the view so it'd init/alloc hundred times.
Not sure why it won't just work in initWithFrame.
I need to know the right way to init and add..!
-(void)queryParseMethod {
self.imageFilesArray = nil;
self.imageFilesArray = [[NSMutableArray alloc]init];
[self.imageFilesArray addObjectsFromArray:objects];
if (!error) {
for (PFObject *object in objects) {
int index = (int)[self.favArray indexOfObject:[object objectId]];
[self.imageFilesArray replaceObjectAtIndex:index withObject:object];
}
[self.favCV reloadData];
}}

Why not just:
if (self.imageFilesArray == nil) {
self.imageFilesArray = [[NSMutableArray alloc] init];
[self.imageFilesArray addObjectsFromArray:objects];
}
And make sure that imageFilesArray is a strong property.

Your most likely problem is that initWithFrame: isn't being called. If this view comes out of a storyboard, then you need to put this in awakeFromNib, since storyboard/nib-loaded objects initialize with initWithCoder:, not their designated initializer.
You generally don't want to try to do initialization in initWithCoder: because it's called too early. awakeFromNib is called after all your IBOutlets are assigned.
It is very common for experienced devs to break initialization out into its own method like this:
- (void)setup {
// Do your setup here
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self setup];
}
}
- (void)awakeFromNib {
[self setup];
}
Doing it this way makes sure that the object is initialized in either case.
Another common solution is lazy initialization, particularly for things like NSMutableArray:
#interface MyView
#property (nonatomic, readonly, strong) NSMutableArray *imageFilesArray;
#end
#implementation MyView
- (NSMutableArray *)imageFilesArray {
if (_imageFilesArray == nil) {
_imageFilesArray = [NSMutableArray new];
}
return _imageFilesArray;
}

Related

Memory leak in [[NSMutableArray alloc] init] even though with ARC

I am working heavily on Memory Fineturning and most of the problems are solved with the help of stackoverflow. But finally I got struck with a serious memory leak with NSMutableArray initialization.
- (NSMutableArray *)children {
if (!_children) {
_children = [NSMutableArray new]; // <-- here is the memory leak
}
return _children;
}
I am working with a project where we are using 100% ARC.
Perticular class initialization is not triggered none other than the main thread (no threading has been used).
but... this is the only place where we are using recurtion
moreover the statments
#property (strong, nonatomic) NSMutableArray *children;
#synthesize children = _children;
are there in the respective .h and .m files...
Waht can be the problem....?
Thanks in advance for you effort...
more info...
- (id)init {
if (self = [super init]) {
[self setIsRoot:NO];
// [self setChildren:[NSMutableArray new]]; // <-- was before, but I moved to custom setter
}
return self;
}
- (id)initAsRoot
{
if (self = [self init]) {
self.level = -1;
self.index = -1;
self.isExpaned = YES;
self.value = #"Root";
self.isRoot = YES;
}
return self;
}

why is this OCUnit test failing?

It's stepping into the ViewDidLoad of the main view controller, and hitting the line calling get all tweets, but I put a breakpoint in the getAllTweets of both the base and derived to see if it just wasn't hitting the derived like I expected.
#implementation WWMainViewControllerTests {
// system under test
WWMainViewController *viewController;
// dependencies
UITableView *tableViewForTests;
WWTweetServiceMock *tweetServiceMock;
}
- (void)setUp {
tweetServiceMock = [[WWTweetServiceMock alloc] init];
viewController = [[WWMainViewController alloc] init];
viewController.tweetService = tweetServiceMock;
tableViewForTests = [[UITableView alloc] init];
viewController.mainTableView = tableViewForTests;
tableViewForTests.dataSource = viewController;
tableViewForTests.delegate = viewController;
}
- (void)test_ViewLoadedShouldCallServiceLayer_GetAllTweets {
[viewController loadView];
STAssertTrue(tweetServiceMock.getAllTweetsCalled, #"Should call getAllTweets on tweetService dependency");
}
- (void)tearDown {
tableViewForTests = nil;
viewController = nil;
tweetServiceMock = nil;
}
The base tweet service:
#implementation WWTweetService {
NSMutableArray *tweetsToReturn;
}
- (id)init {
if (self = [super init]) {
tweetsToReturn = [[NSMutableArray alloc] init];
}
return self;
}
- (NSArray *)getAllTweets {
NSLog(#"here in the base of get all tweets");
return tweetsToReturn;
}
#end
The Mock tweet service:
#interface WWTweetServiceMock : WWTweetService
#property BOOL getAllTweetsCalled;
#end
#implementation WWTweetServiceMock
#synthesize getAllTweetsCalled;
- (id)init {
if (self = [super init]) {
getAllTweetsCalled = NO;
}
return self;
}
- (NSArray *)getAllTweets {
NSLog(#"here in the mock class.");
getAllTweetsCalled = YES;
return [NSArray array];
}
The main view controller under test:
#implementation WWMainViewController
#synthesize mainTableView = _mainTableView;
#synthesize tweetService;
NSArray *allTweets;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
allTweets = [tweetService getAllTweets];
NSLog(#"was here in view controller");
}
- (void)viewDidUnload
{
[self setMainTableView:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
Since you're able to break in the debugger in viewDidLoad, what's the value of the tweetService ivar? If it's nil, the getAllTweets message will just be a no op. Maybe the ivar isn't being set properly or overridden somewhere else.
You should probably use the property to access the tweetService (call self.tweetService) rather than its underlying ivar. You should only ever access the ivar directly in getters, setters, and init (also dealloc if aren't using ARC for some crazy reason).
You also should not call loadView yourself, rather just access the view property of the view controller. That will kick off the loading process and call viewDidLoad.
Also, if you're doing a lot of mocking, I highly recommend OCMock.

NSMutableArray empty after created in init (with code)

#property (nonatomic, strong) NSMutableArray *authorMutableArray;
- (id)init {
self = [super init];
if (self) {
self.authorMutableArray = [[NSMutableArray alloc] initWithObjects:#"First Row", #"Second Row", nil];
for (NSString *string in authorMutableArray) {
NSLog(#"String: %#", string);
}
NSLog(#"Init in Add Model with Author count:%i", [authorMutableArray count]);
}
}
An example of accessing the property. The NSLog always shows the count as 0.
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0) {
if (indexPath.row == [self.addModel.authorMutableArray count] - 1 ) {
NSLog(#"count of %i", [self.addModel.authorMutableArray count]);
return UITableViewCellEditingStyleInsert;
}
else {
return UITableViewCellEditingStyleDelete;
}
}
else {
return UITableViewCellEditingStyleNone;
}
}
The array I'm creating in init is not keeping its values past this method. Any reason why? The for loop will show both objects in the array. If I try to ask this after the init method is called, the array is empty.
Updated: Thank you everyone for your time and eyes. I had forgotten to return self in the init method.
Shouldn't the init method return self ?
In your class' interface file(.h file) declare like this:
#interface Your_Class_Name : UIViewController {
NSMutableArray *authorMutableArray;
}
#property (nonatomic, strong) NSMutableArray *authorMutableArray;
//i dont know why you prefered strong, chose retain and try again please
We aren't dealing with C++ or Java here, the -init method of an object MUST return a value.
This quirk actually allows for some pretty interesting stuff, e.x. the following:
-(id) init {
NSLog(#"Creating new instance of singleton object...");
#if __has_feature(objc-arc)
self = singleton_instance;
#else
[self release];
self = [singleton_instance retain];
#endif
return self;
}
It also allows for class 'posing' of a sort, allowing you to track exactly when an object of a particular class is initialized (that is too deep of a topic for this answer).

NSMutabledictionary not working

I am new to Iphone programming. Please correct me where am I going wrong.
I have two viewcontrollers
viewcontroller1 viewcontroller2
In viewcontroller1,
-(IBAction) getQuestions:(id)sender
{
NSLog(#"In get questions..");
[[self viewcontroller2] initWithData:userInfo];
[self presentModalViewController:viewcontroller2 animated:YES];
[quesions autorelease];
}
In viewController2 I have the following code.
-(id)initWithData:(NSMutableDictionary*)data
{
self = [super init];
if(self)
{
userInfo = [[NSMutableDictionary alloc] initWithDictionary:data];
}
return self;
}
-(IBAction) getQuesionAfterPopUp:(id) sender
{
NSLog(#"In get question..After popup...%#",userInfo);
}
For some reason "userInfo" is null. Why is it null even after using init with data.
You didn't initialize correctly, therefore the instance variable userInfo is not accessible.
Initialization should look like this:
- (id)initWithData:(NSMutableDictionary *)data
{
self = [super init]; // 'self' and it's instance variables are accessible at this point ...
if (self)
{
userInfo = // etc...
}
return self;
}
You might want to read up on this link for more information on how to implement designated initializers. Especially focus on the topic Implementing an Initializer.
in the above code you don't retain your userInfo object. Try
userInfo = [[[NSMutableDictionary alloc] initWithDictionary:data]]retain];
Or if userInfo is a property like:
#property (nonatomic, retain)
Try:
self.userInfo = [[NSMutableDictionary alloc] initWithDictionary:data]];
Which will automatically retain the userInfo. Please note by not calling self you are assigning straight to the instance variable.
Finally, make sure that the data object is not empty

Cannot add object to NSMutableArray

I've checked Google and I haven't found anything that helps.
I'm writing a stack class in Objective-C, the stack is based around an NSMutableArray, however, I cannot add any objects to it, it's not throwing any errors in the console, and there are no compile warnings/errors. Here is my code for the stack object.
#import "Stack.h"
#implementation Stack
#synthesize stack;
- (id)init {
self.stack = [[NSMutableArray alloc] init];
return self;
}
- (void)push:(id)object { [self.stack addObject:object]; }
- (int)size { return [self.stack count]; }
- (id)pop {
id obj = [[[self.stack lastObject] retain] autorelease];
[self.stack removeLastObject];
return obj;
}
- (id)peek { return [self.stack lastObject]; }
#end
Header:
#import <Cocoa/Cocoa.h>
#interface Stack : NSObject {
NSMutableArray *stack;
}
- (void)push:(id)object;
- (int)size;
- (id)pop;
- (id)peek;
#property (nonatomic, retain) NSMutableArray *stack;
#end
For the rest of the code, if I call [test_stack size], it returns zero, no matter how many times I push an object, and if I call pop or peek, it simply returns (null).
#import "TRIAL_Stack_Ctrl.h"
#implementation TRIAL_Stack_Ctrl
#synthesize test;
- (IBAction)push:(id)sender {
[test_stack push:[input stringValue]];
}
- (IBAction)pop:(id)sender {
[label setStringValue:[NSString stringWithFormat:#"%#", [test_stack pop]]];
}
- (IBAction)peek:(id)sender {
[label setStringValue:[NSString stringWithFormat:#"%#", [test_stack peek]]];
}
- (IBAction)size:(id)sender {
[label setStringValue:[NSString stringWithFormat:#"%d", [test_stack size]]];
}
#end
This leads me to believe that it's not pushing the object, is there anything I am doing wrong?
Change:
- (id)init {
self.stack = [[NSMutableArray alloc] init];
return self;
}
to:
- (id)init {
self = [super init];
if (self) {
stack = [[NSMutableArray alloc] init];
}
return self;
}
If that really is the full implementation of your TRIAL_Stack_Ctrl class, you're not assigning the test stack instance variable anywhere, so it's nil.
Apart from leaking the NSMutableArray, and unnecessary use of self.stack, it looks ok. So it seems your problem is probably in TRIAL_Stack_Ctrl class that you don not show the code to.
If you feel like you are going crazy assertions can help you get to the bottom of what is going on.
- (void)push:(id)object {
NSParameterAssert(object);
[stack addObject:object];
NSAssert([stack count], #"array is empty");
}
They compile away to nothing in release code.
This leads me to believe that it's not pushing the object, is there anything I am doing wrong?
Incorrect assumption. removeLastObject throws an NSRangeException if the mutable array has no objects in it. If you do not see a range exception, when you try to pop an empty stack, the stack itself must be nil.
Can we see the .h for the implementation? I see you are synthesizing something called 'test' but all the operations are done on something called 'test_stack'. Naming problem? If so, it should probably also be 'self.test_stack'.