Adding an object to Mutable array is not possible - objective-c

I am trying add a Song* object to a Mutable array and I am stumped as the count of the array is not increasing in spite of adding the object.
Song.h
#import <Foundation/Foundation.h>
#interface Song : NSObject
#property(copy, nonatomic) NSString *title, *album, *artist;
#property(copy, nonatomic) NSNumber *playTime;
#end
Song.m
#import "Song.h"
#implementation Song
#end
Playlist.h
#import <Foundation/Foundation.h>
#class Song;
#interface Playlist : NSObject
#property(copy, nonatomic) NSMutableArray *playListArray;
-(void) addSong: (Song *) tempSongToBeAdded;
-(void) removeSong: (Song *) tempSongToBeremoved;
-(void) listOfSongs;
-(NSUInteger) entries;
#end
Playlist.m
#import "Playlist.h"
#import "Song.h"
#implementation Playlist
-(void) addSong: (Song *) tempSongToBeAdded{
NSLog(#"%s song is being added.", [tempSongToBeAdded.title UTF8String]);
[self.playListArray addObject:tempSongToBeAdded];
}
-(void) removeSong: (Song *) tempSongToBeremoved{
[self.playListArray removeObject:tempSongToBeremoved];
}
-(NSUInteger) entries{
return [self.playListArray count];
}
-(void) listOfSongs{
NSLog(#"Hi");
for (Song *tempSong in self.playListArray) {
NSLog(#"title: %s", [tempSong.title UTF8String]);
}
}
#end
Main.m
#import <Foundation/Foundation.h>
#import "Song.h"
#import "Playlist.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
Song *song1 = [[Song alloc] init];
song1.title = #"Manasa";
song1.album = #"Ye Maya Chesava";
song1.artist = #"A. R. Rahman";
song1.playTime = [NSNumber numberWithDouble:4.56];
Playlist *playlist1 = [[Playlist alloc] init];
[playlist1 addSong:song1];
NSLog(#"The total number of songs are %lu",[playlist1 entries]);
[playlist1 listOfSongs];
}
return 0;
}
I am getting the entries in the playlist as 0 and and the list of songs as empty. I am not getting any compile errors and I have no idea why the objects are not getting added to the array.

Your variable playListArray is never initialized and is always nil. You need to initialize it using:
playListArray = [[NSMutableArray] alloc] init];
You can add an init method in your Playlist class where you initialize this object.
- (id)init
{
self = [super init];
if (self)
{
playListArray = [[NSMutableArray] alloc] init];
}
return self;
}
EDIT:
The problem seems to be how you declared the property
#property(copy, nonatomic) NSMutableArray *playListArray;
It is declared as copy, that means that even when you do playListArray = [[NSMutableArray] alloc] init], your variable playListArray gets a copy of the initialized array, but the copy protocol is inherited from NSArray, not from NSMutableArray, so you get an immutable array. You can check this in the NSMutableArray documentation. You need to change copy for retain (you're not using ARC, right?).
In fact I see that you're using copy for most of your properties, if there's no particular reason for this, I would change them to retain.

Related

Using custom method to add objects to NSMutableArray Objective C

I am new to Objective C, I'm trying to add objects to NSMutableArray that I can use multiple times on my project. I have a Model class as
History.h
import
#interface History : NSObject
#property (nonatomic) NSString *itemName;
#property (nonatomic) int quantity;
#property (nonatomic) double total;
#property (nonatomic) NSDate *purchaseDate;
- (instancetype)initWithName: (NSString*)itemName withQuantity:(int)quantity withTotal:(double) total withPurchaseDate:(NSDate*) purchaseDate;
#end
History.m
#import "History.h"
#implementation History
-(instancetype)initWithName: (NSString*)iName withQuantity:(int)iQuantity withTotal:(double) iTotal withPurchaseDate:(NSDate*) iPdate {
self = [super init];
if(self) {
self.itemName = iName;
self.quantity = iQuantity;
self.quantity = iQuantity;
self.purchaseDate = iPdate;
}
return self;
}
#end
Repository.h
#import <Foundation/Foundation.h>
#interface Repository : NSObject
#property (nonatomic) NSMutableArray *itemHistory;
-(void) pushToArray:(NSString *)name withQuantity:(int)qty withTotal:(double) total withPurchaseDate:(NSDate*) pDate;
#end
Repository.m
#import "Repository.h"
#import "History.h"
#interface Repository()
//#property (nonatomic) NSMutableArray *itemHistory;
#end
#implementation Repository
-(NSMutableArray *) itemHistory {
if(_itemHistory == nil) {
_itemHistory = [[NSMutableArray alloc] init];
}
return _itemHistory;
}
This is my method that I want to use to add objects to the MutableArray.
-(void) pushToArray:(NSString *)name withQuantity:(int)qty withTotal:(double) total withPurchaseDate:(NSDate*) pDate {
self.itemHistory = [[NSMutableArray alloc] init];
History *obj = [[History alloc] init];
obj.itemName = name;
obj.quantity = qty;
obj.total = total;
obj.purchaseDate = pDate;
[self.itemHistory addObject:obj];
}
#end
Thank you for your help in advance.
Every time you call pushToArray:... you are replacing the existing itemHistory with a new, empty, mutable array. You'll only ever see the last item to be pushed in that array.
However, you also don't need to lazily initialize _itemHistory. Just create an instance in your init method and be done with it. Saves confusion and refactoring hell.
In your Repository class, simply implement the designated initializer:
- (instancetype) init
{
if (self=[super init]) {
_itemHistory = [[NSMutableArray alloc] init];
}
return self;
}
Uncomment the property:
#interface Repository()
#property (nonatomic) NSMutableArray *itemHistory;
#end
And remove this from the -pushToArry:... method:
//self.itemHistory = [[NSMutableArray alloc] init];
If it still doesn't work, you need to show how you are logging the failure.

NSMutableArray resetting itself when WindowDidLoad is done

When I pass a NSMutableArray from a controller class to a NSWindowController class using #property and #synthesize I am able to use the objects of the array in the windowDidLoad method.
However, after the method is done and I click a button on the window triggerig an IBAction, the passed value is nil.
Can anyone explain me why this is happening and how I can preserve the NSMutableArray?
Here is the code:
passClass.h
#import <Foundation/Foundation.h>
#class ResultWindowController;
#interface passClass : NSObject {
#private
IBOutlet NSTextField *searchField;
ResultWindowController *resultWindowController;
}
- (IBAction)passIt:(id)sender;
#end
passClass.m
#import "passClass.h"
#import "ResultWindowController.h"
#implementation passClass
- (IBAction)passIt:(id)sender {
NSString *searchString = searchField.stringValue;
NSMutableArray array = [[NSMutableArray alloc]init];
[array addObject:searchString];
[array addObject:searchString];
if(!resultWindowController) {
resultWindowController = [[ResultWindowController alloc] initWithWindowNibName:#"ResultWindow"];
resultWindowController.array =[[NSMutableArray alloc]initWithArray:array copyItems:YES];
[resultWindowController showWindow:self];
}
}
#end
ResultWindowController.h
#import <Cocoa/Cocoa.h>
#interface ResultWindowController : NSWindowController <NSTableViewDataSource> {
IBOutlet NSTableView *resultView;
NSMutableArray *resultList;
//NSMutableArray *array;
}
- (IBAction)returnValue:(id)sender;
#property (nonatomic,strong) NSMutableArray *array;
#end
ResultWindowController.m
#import "Results.h"
#interface ResultWindowController ()
#end
#implementation ResultWindowController
//#synthesize array;
- (id)initWithWindow:(NSWindow *)window
{
self = [super initWithWindow:window];
if (self) {
// Initialization code here.
resultList = [[NSMutableArray alloc] init];
}
return self;
}
- (void)windowDidLoad
{
[super windowDidLoad];
for (NSInteger i = 0; i< [array count];i++)
{
Results *result = [[Results alloc]init];
result.resultName = [self.array objectAtIndex:i];
[resultList addObject:result];
[resultView reloadData];
NSLog (#"self.array: %#", self.array);
// works fine, tableview gets populated, array is correct
}
}
- (NSInteger) numberOfRowsInTableView:(NSTableView *)resultView{
return [resultList count];
}
- (id)tableView:(NSTableView *)resultView objectValueForTableColumn:(NSTableColumn *)resultColumn row:(NSInteger)row{
Results *result = [resultList objectAtIndex:row];
NSString *identifier = [resultColumn identifier];
return [result valueForKey:identifier];
}
- (IBAction)selectedSeries:(id)sender {
NSLog (#"self.array: %#", self.array);
//when I break here the array is nil
}
#end
Here is the NSLog result:
2013-12-26 10:36:49.487 MyProgram[545:303] self.array: (
"test",
"test"
)
2013-12-26 10:37:24.044 MyProgram[545:303] self.array: (null)
Try to remove NSMutableArray *array; from ResultWindowController class declaration and leave only the property declaration for it.
Or you could try initiating the array property in your ResultVWindowsContorller init class and in the - (IBAction)passIt:(id)sender just add objects to array.
I honestly can't see how this works at all unless, in -windowDidLoadNib you are expecting array to be empty.
When you synthesise a property, the default name of the instance variable that is used is prefixed by an underscore. Thus the class in your code has two instance variables, array and _array.
There are several ways to fix this. Here's what I think what you should do is delete the instance variable in your interface definition. Then you'll start getting compilation errors every for each time you use it. Fix them by using the property instead, so for example, the line
result.resultName = [array objectAtIndex:i];
in -windowDidLoadNib becomes
result.resultName = [self.array objectAtIndex:i];

I'm having problems using a Singleton to pass an array in Objective-c. (code included)

So I'm creating an array called fruits which I would like to share between multiple views. This is my code:
#import <foundation/Foundation.h>
#interface MyManager : NSObject {
NSMutableArray *fruits;
}
#property (nonatomic, retain) NSMutableArray *fruits;
+ (id)sharedManager;
#end
#import "MyManager.h"
static MyManager *sharedMyManager = nil;
#implementation MyManager
#synthesize fruits;
#pragma mark Singleton Methods
+ (id)sharedManager {
#synchronized(self) {
if (sharedMyManager == nil)
sharedMyManager = [[self alloc] init];
}
return sharedMyManager;
}
- (id)init {
if ((self = [super init])) {
fruits = [[NSMutableArray alloc] init];
}
return self;
}
-(void) dealloc{
self.fruits = nil;
[super dealloc];
}
#end
Now I'm using the following code so that I can use workouts in the new view
#import "MyManager.h"
#interface Chest : UIViewController {
IBOutlet MyManager *fruits;
}
#property (nonatomic, retain) IBOutlet MyManager *fruits;
-(IBAction) goToList: (id) sender;
#end
When a button is clicked, goToList is called, and I populate my array, fruits
#import "Chest.h"
#implementation Chest
#synthesize fruits;
-(IBAction) goToList:(id)sender{
MyManager *fruits = [MyManager sharedManager];
NSString *filePath;
NSString *fileContents;
filePath = [[NSBundle mainBundle] pathForResource:#"chest_strength" ofType:#"csv"];
fileContents = [[NSString alloc] initWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
fruits = [fileContents componentsSeparatedByString:#"\n"];
}
When I output the elements of *fruits in this view, everything works fine. Now when I try to access this same variable in the other view, it says the array is null. Here's the code for the second view:
#interface List : UIViewController {
IBOutlet MyManager *fruits;
}
#property (nonatomic, retain) IBOutlet MyManager *fruits;
#end
#import "List.h"
#import "MyManager.h"
#implementation List
#synthesize fruits
NSLog(#"%#", fruits); //This is the part that isn't displaying correctly. I'm getting a null here
So my question is, how do I do this so that I can get the array fruits that I populated in Chest and use it in List so that I can display the contents of the array in that view?
Thank you to everybody who answers. This problem is seriously bogging me down and I need to finish this project ASAP. Much appreciated.
You've changed a few things in this question but the fundamental problem remains: the array is a property of your singleton, and you are not treating it as such.
Whenever you refer to the array, outside of the singleton, do it like this:
[MyManager sharedManager].fruits
If you are accessing it frequently, you can create a local ivar, but you certainly wouldn't have it as an IBOutlet, which you are doing in your last code sample. How is that ever going to be set?

NSMutableArray KVC/KVO question

This is a sample from book "Cocoa Programming For Mac Os X 3rd(HD)" chapter 7 "Key-Value Coding. Key-Vaule Observing
Here is the code:
Person.h:
#import <Foundation/Foundation.h>
#interface Person : NSObject {
NSString *personName;
float expectedRaise;
}
#property (readwrite, copy) NSString *personName;
#property (readwrite) float expectedRaise;
#end
Person.mm:
#import "Person.h"
#implementation Person
#synthesize expectedRaise;
#synthesize personName;
- (id)init
{
[super init];
expectedRaise = 0.05;
personName = #"New Person";
return self;
}
- (void)dealloc
{
[personName release];
[super dealloc];
}
#end
MyDocument.h:
#import <Cocoa/Cocoa.h>
#interface MyDocument : NSDocument
{
NSMutableArray *employees;
}
#property (retain) NSMutableArray *employees;
#end
MyDocument.mm:
#import "MyDocument.h"
#import "Person.h"
#implementation MyDocument
#synthesize employees;
- (id)init
{
if (![super init])
return nil;
employees = [[NSMutableArray alloc] init];
return self;
}
- (void)dealloc
{
[employees release];
[super dealloc];
}
- (void)windowControllerDidLoadNib:(NSWindowController *) aController
#end
And the sample works fine.(A blank table at first and you can add or delete record).
Now I tried to add some records to the array so that the blank table would have
someting in it at first.
Here's what I'v tried(inside the init method):
[self willChangeValueForKey:#"employees"];
Person *p1 = [[Person alloc] init];
[employees addObject: [NSData dataWithBytes: &p1 length: sizeof(p1)]];
[self didChangeValueForKey:#"employees"];
But when I build and wrong I got the error msg:
[<NSConcreteData 0x422bf0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key personName.
......
Can any one help me out of here? Thanks in advance ^_^
That seems like a very reasonable response... you added NSData to your array named employees; guessing from the names, and from the KVC, you probably meant to add p1 to your array instead. So, try:
[employees addObject:p1];

Objective C one class not seeing the other

I have these two classes MobRec & MobDef and I want to reference an array pointer of (MobDef) *mobInfo from MobRec. #import the mobdefs.h file in MobRec.h or .m but no luck any ideas?
MobRec.h
// Basic class unit
#interface MobRec : NSObject {
NSString *mName;
int speed;
}
#end
MobDef.h
// Master Class holding an array of units
#interface MobDef : NSObject {
NSMutableArray *mobInfo;
}
#property(retain) NSMutableArray *mobInfo;
#end
MobDef.m
#synthesize MobInfo;
- (id)init { // to add a new node and initialize it
mobInfo = [[NSMutableArray alloc] init];
MobRec *aNewMobRec = [[MobRec alloc] init];
[mobInfo addObject:aNewMobRec];
[aNewMobRec release];
}
The problem is that individual files have no knowledge of other files in your project, since Objective-C is a derivative of C. You need to #import the header files of any other classes that you need to use:
// ModDef.m
#import "MobDef.h"
#import "ModRec.h"
#implementation MobDef
#synthesize mobInfo; // case matters here
- (id)init
{
mobInfo = [[NSMutableArray alloc] init];
MobRec* aNewMobRec = [[MobRec alloc] init];
[mobInfo addObject:aNewMobRec];
[aNewMobRec release];
}
#end
Well, your #synthesize doesn't match #property declaration - you're declaring properties for mobInfo but generating synthesized accessors for MobInfo.
Of are you getting some other error?