NSMutableArray *tblContents = [NSMutableArray arrayWithObjects: #"1", #"2", #"3", nil];
[tblContents addObject:txtNewTableRow.text];
My app is crashing at line 2.
Error message in console is
'NSInvalidArgumentException', reason: '-[NSCFString addObject:]: unrecognized selector sent to instance xxx
BTW, it works alright if i replace arraywithobjects initialization with alloc & init!
I am simply creating a mutable array and adding an object to it. Whats the problem in there?
Thanks
Sridhar Reddy
Full code:
.h:
#import <UIKit/UIKit.h>
#interface TableStarterViewController : UIViewController
<UITableViewDelegate, UITableViewDataSource>
{
NSMutableArray *tblContents;
IBOutlet UITextField *txtNewTableRow;
IBOutlet UITableView *tblMain;
}
#property (nonatomic, retain) NSMutableArray *tblContents;
#property (nonatomic, retain) UITextField *txtNewTableRow;
#property (nonatomic, retain) UITableView *tblMain;
-(IBAction) addRowToTable;
#end
.m:
#import "TableStarterViewController.h"
#implementation TableStarterViewController
#synthesize tblContents;
#synthesize txtNewTableRow;
#synthesize tblMain;
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [tblContents count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"cell"];
cell.textLabel.text = [tblContents objectAtIndex:indexPath.row];
return cell;
}
-(IBAction) addRowToTable
{
[tblContents addObject:txtNewTableRow.text];
[tblMain reloadData];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
tblContents = [NSMutableArray arrayWithObjects: #"1", #"2", #"3", nil];
[super viewDidLoad];
}
Thats all code.
Your are not retaining the array and it is being autoreleased before you are using it. Make sure to retain it after you get the pointer back from arrayWithObjects.
Also, it's not clear to me that arrayWithObjects will return a mutable array. Which, if not, will cause further problems.
Edit 1:
Alloc and Init return an object with retain count 1; arrayWithObjects returns an object with retain count 0.
Edit 2:
I pulled out Xcode and verified that [NSMutableArray arrayWithObjects:] return an NSMutableArray (or according to Xcode a __NSArrayM)
instead of,
tblContents = [NSMutableArray arrayWithObjects: #"1", #"2", #"3", nil];
try this,
tblContents = [NSMutableArray initWithObjects: #"1", #"2", #"3", nil];
As mentioned by aepryus, arrayWithObjects is inherited from NSArray and it might actually be returning NSArray. Hence the problem.
Anyone knows how to init NSMutableArray with objects?
Related
I have been able to make the listview show a single field of data using parts of the code like below.
NSMutableArray *array;
..
..
array = [[NSMutableArray alloc] init];
[array addObject:#"John Doe"];
However I want to keep several fields, like:
Name
ID
Date of Birth
I assume the NSMutableArrary is a NSString but I need something like a struct in C that holds the fields I need.
The ID would be "Hidden" but I need to access it when the user clicks on the line. How I access the ID and the other fields? How do I set this up so the list has the information?
Does anyone have any example code that might explain how to do this?
EDIT #1: Thanks for the comments, but I am too new to iPhone and really need to find example code on how to do this. While the comments make it sound like can do this, I dont know where to start. Can someone post example code for the idea of 3 fields?
EDIT #2: I have tried everything so far, is the the correct way to do this or should I use the ideas below?
Userrec.m
#import "UserRec.h"
#implementation Userrec
#synthesize Name, ID;
-(id)initWithName:(NSString *)n ID:(NSString *)d {
self.Name = n;
self.ID = d;
return self;
}
#end
UserRec.h
#import <UIKit/UIKit.h>
#interface Userrec : NSObject {
NSString *Name;
NSString *ID;
}
#property (nonatomic, retain) NSString *Name;
#property (nonatomic, retain) NSString *ID;
-(id)initWithName:(NSString *)n ID:(NSString *)d;
#end
UserList.m
#synthesize userrecs;
…
- (void)viewDidLoad {
[super viewDidLoad];
NSString *Name = #"Name";
NSString *ID = #"IID";
Userrec *userrec = [[Userrec alloc] initWithName:Name ID:ID ];
[userrecs addObject:userrec];
NSLog(#"Count %d",[userrecs count]);
[userrec release];
NSLog(#"Count %d",[userrecs count]);
}
After I addobject and check the count its = 0. So I assume something is wrong?
NSMutableDictionary is the best way to go. You can do something as follows:
NSMutableDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:#"John Doe", #"Name", [NSNumber numberWithInt:5], #"ID", nil];
You can keep adding as many fields as you like with that same template, even NSArray objects. I'd look up the documentation if you have any more trouble. Remember, you can only store pointers to objects in an NSDictionary. Things like
NSMutableDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:#"John Doe", #"Name", 5, #"ID", nil];
won't work. Good Luck!
Take a look at an NSMutableDictionary it seems like the exact thing you would want to use
Edit:
Here's some sample code
NSMutableArray *myData = [[NSMutableArray alloc] init];
NSMutableDictionary *myRow = [[NSMutableDictionary alloc] init];
[myRow setObject:#"John Doe" forKey:#"Name"];
[myRow setObject:#"4738" forKey:#"ID"];
[myRow setObject:#"1/23/45" forKey:#"DOB"];
[myData addObject:myRow];
[myRow release];
//Repeat from dictioanry alloc through release for each row you need to add
To display this in a UITableView, you need to have a UITableViewController class. In there override the cellForRowAtIndexPath: function. here is a simple implementation of that function
-(UITableViewCell*) tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger row = [indexPath row];
static NSString *kCellID = #"cellID";
UITableViewCell *cell = nil;
cell = [tableView dequeueReuseableCellWithIdentifier:kCellID];
if ( cell == nil )
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellID] autorelease];
}
NSMutableDictionary curRow = [myData objectAtIndex:row];
cell.textLabel.text = [curRow objectForKey:#"Name"];
return cell;
}
I have an NSMutableArray defined as a property, synthesized and I have assigned a newly created instance of an NSMutableArray. But after this my application always crashes whenever I try adding an object to the NSMutableArray.
Page.h
#interface Page : NSObject
{
NSString *name;
UIImage *image;
NSMutableArray *questions;
}
#property (nonatomic, copy) NSString *name;
#property (nonatomic, retain) UIImage *image;
#property (nonatomic, copy) NSMutableArray *questions;
#end
Page.m
#implementation Page
#synthesize name, image, questions;
#end
Relevant code
Page *testPage = [[Page alloc] init];
testPage.image = [UIImage imageNamed:#"Cooperatief leren Veenman-11.jpg"];
testPage.name = [NSString stringWithString:#"Cooperatief leren Veenman-11.jpg"];
testPage.questions = [[NSMutableArray alloc] init];
[testPage.questions addObject:[NSNumber numberWithFloat:arc4random()]];
The debugger reveals that the moment I use testPage.questions = [[NSMutableArray alloc] init]; the type of testPage.questions changes from NSMutableArray* to __NSArrayL* (or __NSArrayI*, not sure). I suspect this to be the problem, but I find it extremely odd. Anyone know what's happening here?
The problem is that you've declared the property as copy. This means your setter is going to be implemented something like this:
- (void) setQuestions:(NSMutableArray *)array {
if (array != questions) {
[questions release];
questions = [array copy];
}
}
The kicker here is that if you -copy an array (whether immutable or mutable), you will always get an immutable NSArray.
So to fix this, change the property to be retain instead of copy, and also fix this memory leak:
testPage.questions = [[NSMutableArray alloc] init];
It should be:
testPage.questions = [NSMutableArray array];
#property (nonatomic, copy) This setter declaration "copy" probably cast to NSArray why not retain or assign? I would retain anyway
You can also create a mutable copy method like so:
- (void)setQuestions:(NSMutableArray *)newArray
{
if (questions != newArray)
{
[questions release];
questions = [newArray mutableCopy];
}
}
This is really twisting my mind… I'm trying to access an NSMutableArray in an IBAction which I defined in viewDidLoad. Unfortunately I keep getting a EXC_BAD_ACCESS.
I'm new to all this so I'd really appreciate some insight in what I'm doing wrong.
Below find the corresponding code excerpts.
CounterViewController.h:
#interface CounterViewController : UIViewController{
NSMutableArray *countHistoryArray;
}
#property(nonatomic, retain) NSMutableArray *countHistoryArray;
CounterViewController.m:
#implementation CounterViewController
#synthesize countHistoryArray;
- (void)viewDidLoad {
[super viewDidLoad];
//Fill array with some dummy data
self.countHistoryArray = [[NSMutableArray alloc] init];
NSDate *now = [[[NSDate alloc] init] autorelease];
CurrentCount *historicCount = [[[CurrentCount alloc]
initWithCount:[NSNumber numberWithInteger:22]
description:#"Testcount"
dateAndTime:now] autorelease];
[self.countHistoryArray addObject: historicCount];
//Do some logging - everything is working fine here!
NSLog(#"%#", [self.countHistoryArray description]);
}
//Later on we click on a button and want to use the array
- (IBAction)doSomeStuff {
//Let's look at the array again - and now it crashes with EXC_BAD_ACCESS
NSLog(#"%#", [self.countHistoryArray description]);
}
Thanks a lot!
Manuel
EDIT Additional code as asked for by #jamapag
CurrentCount.h
#import <Foundation/Foundation.h>
#interface CurrentCount : NSObject {
NSNumber *counterLevel;
NSString *description;
NSDate *dateAndTime;
}
- (id)initWithCount:(NSNumber *)newCounterLevel description:(NSString *)newDescription dateAndTime:(NSDate *)newDateAndTime;
#property(nonatomic, copy) NSNumber *counterLevel;
#property(nonatomic, copy) NSString *description;
#property(nonatomic, copy) NSDate *dateAndTime;
#end
CurrentCount.m
#import "CurrentCount.h"
#implementation CurrentCount
#synthesize counterLevel;
#synthesize description;
#synthesize dateAndTime;
- (id)initWithCount:(NSNumber *)newCounterLevel description:(NSString *)newDescription dateAndTime:(NSDate *)newDateAndTime{
self = [super init];
if(nil != self){
self.counterLevel = newCounterLevel;
self.description = newDescription;
self.dateAndTime = newDateAndTime;
}
return self;
}
-(void) dealloc{
self.counterLevel = nil;
self.description = nil;
self.dateAndTime = nil;
[super dealloc];
}
#end
Are you sure that your code actually looks like this?
- (IBAction)doSomeStuff {
//Let's look at the array again - and now it crashes with EXC_BAD_ACCESS
NSLog(#"%#", [self.countHistoryArray description]);
}
Your question title says "NSMutableArray count causes EXC_BAD_ACCESS" - if that line of code actually says NSLog(#"%#", [self.countHistoryArray count]);, you'll almost certainly get a crash, since NSLog will attempt to treat a primitive type (the type returned by -[NSArray count]) as an object. In order to use -[NSArray count] in NSLog, use %u instead of %#:
- (IBAction)doSomeStuff {
// This time it should work!
NSLog(#"Array Count = %u", [self.countHistoryArray count]);
}
Remove autorelease from:
currentCount *historicCount = [[[CurrentCount alloc]
initWithCount:[NSNumber numberWithInteger:22]
description:#"Testcount"
dateAndTime:now] autorelease];
It looks like you are accidentally releasing countHistoryArray somewhere. Try removing all calls to it except for those two you showed. Additionally you can try enabling zombies to debug the problem.
Oh and by the way you probably don't really want a public NSMutableArray property and if you do you probably want it to be copy, not retain. Otherwise incapsulation kinda goes down the drain.
I know this question has already been solved and accepted but its for others who are or will face this issue.
I was facing the same issue, I tried all solutions but no solution worked for me. The project I am working on is NON-ARC.
I tried and made a simple change in property
Previously my property for NSMUTABLEARRAY was
#property (nonatomic, assign) NSMutableArray * dataArray;
I changed it to:
#property (nonatomic, retain) NSMutableArray * dataArray;
Changed it from ASSIGN to RETAIN
And it solved my problem
I am getting errors when trying to add items to a NSMutableArray which is encapsulated within an object.
Code follows:
#import <Foundation/Foundation.h>
#interface TestObject : NSObject {
NSMutableArray *myArray;
}
#property (nonatomic, retain) NSMutableArray *myArray;
#end
#import "TestObject.h"
#implementation TestObject
#synthesize myArray;
- (id) init {
if(self= [super init]){
// Initialise the Mutable Array
myArray = [[NSMutableArray alloc] init];
}
return self;
}
- (void) dealloc {
[super dealloc];
[myArray release];
}
#end
Calling:
TestObject *testObject = [[TestObject alloc] init];
NSString *someString = #"blah blah blah";
NSLog(#"%#", someString);
[testObject.myArray addObject:someString];
NSLog(#"Test Object Array Count: %#", [testObject.myArray count]);
[testObject release];
Can anyone tell me why this throws an error when calling count?
I have also tried the copy the Mutable Array to a local variable and get the same result when calling count on the local variable.
Warning warning warning!!!
[super dealloc] is the last thing you should do in your -dealloc method, not the first!
It's a good thing it just showed a warning, when I have done the same it has crashed.
The reason is that %# is an object placeholder. But the count method returns NSInteger which is a primitive datatype and the placeholder for it is %d, as you have correctly noted in the comment.
I am developing iPhone Application.
MyApplicationData.h
#import <Foundation/Foundation.h>
#interface MyApplicationData : NSObject {
NSMutableArray* appData;
}
#property (retain) NSMutableArray* appData;
-(void)loadData;
-(void)addAppDataItemPrice:(NSString*)price itemCategory:(NSString*)category itemDate:(NSDate*)date;
-(void)forDebug;
+(id)instance;
#end
MyApplicationData.m
#import "MyApplicationData.h"
#implementation MyApplicationData
+ (id)instance
{
static MyApplicationData* _instance = nil;
if (!_instance) {
_instance = [[MyApplicationData alloc] init];
}
return _instance;
}
-(void)loadData{
appData = [NSMutableArray array];
NSLog(#"%#",appData);
}
-(void)forDebug{
}
-(void)addAppDataItemPrice:(NSString*)price itemCategory:(NSString*)category itemDate:(NSDate*)date{
NSLog(#"%#", appData);
[appData addObject:#"1"];
NSLog(#"%#", appData);
}
#end
another class
[[MyApplicationData instance] loadData];
one another class
[[MyApplicationData instance] addAppDataItemPrice:price itemCategory:category itemDate:date];
log
[Session started at 2009-11-03 21:04:41 +0900.]
2009-11-03 21:04:44.742 XXX[24002:207] (
)
2009-11-03 21:04:46.612 XXX[24002:207] (null)
It is not executed. What is the cause?
I think this line might be the cause:
appData = [NSMutableArray array];
try this instead:
appData = [[NSMutableArray alloc] init]
You'll want to make sure you release it as well when your MyApplicationData instance is destroyed (not critical in this case since it's a singleton, but still good practice)
It looks like your array is getting autoreleased after the method:
[[MyApplicationData instance] loadData];
I think it should be a member of the class, you can use the property syntax to help.
Set it up in the header file as:
#property (nonatomic, retain) NSMutableArray *appdata;
Then in the implementation:
#synthesize appdata;
Assign it as follows:
-(void)loadData{
self.appData = [NSMutableArray array];
}
Don't forget to release it in your dealloc method
When you set it in your code you can call it like the following:
[self.appData addObject:#"1"];