Error in accessing global declared NSArray values in class methods - iphone

I have problem in fetching the element from array,
I have declared NSArray *array globally, also tried through myfile.h file property, but I'm not able to access array element in my view controller setCode method.
NSArray *array;
//this is global array also i tried in my.h file
//#property(nonatomic, retain) NSArra *array;
//and by accessing it #synthesize array; also not works for me.
-(void)viewDidLoad
{
array = [NSArray arrayWithObjects:#"sssss", #"hjjjjj", #"kkkkkk"];
[self setCode];
}
-(void)setCode
{
NSString *code = [array objectAtIndex:0];
NSLog(#"code %#",code);
}
#end
It throwing some errors:
2013-08-05 16:25:28.429 test_project_ios_31st_july[2409:c07] -[__NSMallocBlock__ objectAtIndex:]: unrecognized selector sent to instance 0x9c82350
2013-08-05 16:25:28.430 test_project_ios_31st_july[2409:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSMallocBlock__ objectAtIndex:]: unrecognized selector sent to instance 0x9c82350'
*** First throw call stack:
(0x23fb012 0x1c98e7e 0x24864bd 0x23eabbc 0x23ea94e 0x283f 0x17594f9 0x24550c5 0x23afefa 0x168dbb2 0x16a0e6b 0xdb9f 0x16d2417 0x16ebb24 0x16a0d60 0x174da8a 0x43ac2 0x16d2417 0x16ebb24 0x16a0d60 0x174da8a 0x464d5 0x17594f9 0x24550c5 0x23afefa 0x16a0a0c 0xa3d0e6 0x206353f 0x2075014 0x20657d5 0x23a1af5 0x23a0f44 0x23a0e1b 0x2ad87e3 0x2ad8668 0xbdcffc 0x2192 0x20c5)
libc++abi.dylib: terminate called throwing an exception

Please try following code:
NSArray *array;
-(void)viewDidLoad
{
array = [NSArray arrayWithObjects:#"sssss", #"hjjjjj", #"kkkkkk"];
[array retain];
[self setCode];
}
-(void)setCode
{
NSString *code = [array objectAtIndex:0];
NSLog(#"code %#",code);
[array release];
}
#end

You are declaring another object from the array inside your viewDidLoad, so your global array object will never get allocated, you need to remove the declaration as below:
-(void)viewDidLoad
{
array = [NSArray arrayWithObjects:#"sssss", #"hjjjjj", #"kkkkkk"];
int i;
[self setCode];
}
And by the way the setCode doesn't do anything rather than printing!, you can change its name to printCode.

Add
#interface PeopelListViewController : UIViewController
{
NSArray *array;
}
//in my.h file
//#property(nonatomic, retain) NSArra *array;
//and #synthesize array;
just you need to Put nil at the end of your NSArray.
such like
self.array = [NSArray arrayWithObjects:#"sssss", #"hjjjjj", #"kkkkkk", nil];

first you declare an array in implementation (.m file) like this
#implementation : myviewcontroller {
NSArray *array;
}
then initialize it like
array = [NSArray arrayWithObjects:#"sssss", #"hjjjjj", #"kkkkkk", nil];
it must work

What you did is to create a reference - local, here in this method.
-(void)viewDidLoad
But in your -(void)setCode method, you are accessing your global variable .
The global variable is not yet allocated a memory, neither initialized hence the error.
So you need to understand the scope of variables. Local scope preceeds global scope. Anyways you are working with two different array objects.
Change this in your viewDidload implementation to make it work:
// No NSArray at front that will make it an another array object
array = [NSArray arrayWithObjects:#"sssss", #"hjjjjj", #"kkkkkk"];

Related

I can not access my variable in EasyTableView delegate method

I use "EasyTableView" which is an extend UITableView. I encounter a problem as below:
- (void)viewDidLoad
{
NSArray *array = [[NSArray alloc] initWithObjects:#"14.jpg",nil];
photos = array;
[array release];
[photos objectAtIndex:0]; //this "photos" can be access
}
but when i try to access the "photos" in the delegate method:
- (void)easyTableView:(EasyTableView *)easyTableView setDataForView:(UIView *)view forIndexPath:(NSIndexPath *)indexPath {
NSInteger r = [indexPath row]; // r = 0
NSString *imagePath = [photos objectAtIndex:r]; //this line cause : reason: '-[CALayer objectAtIndex:]: unrecognized selector sent to instance
}
Why the result to access photos is different? How can i fix it?
use photos as property as
#property (nonatomic, retain) NSMutableArray* photos;
and in implementation
#synthesize photos = photos;
it will be accessible in delegate now
The photos variable isn't retaining the array you assign to it. When it is deallocated, the memory is being re-used to point to a CALayer object. If photos is a retained property, you should use self.photos = array; to make the assignment. If it's just a simple variable, then allocate it directly instead of using array.

Saving Arrays Between Classes

Currently attempting to save an array that is populated according to which cells in a UITableView are chosen and saving this array in an instance of a seperate object. I am getting the array to populate just fine, however, my save method, which is an IBAction that is invoked by clicking on a Bar Button doesn't seem to be working. Here is some code:
-(IBAction)saveWorkout:(id)sender {
Workouts *new = [[Workouts alloc] init];
[new addNewWorkout:customWorkout];
[customWorkout removeAllObjects];
}
This code is from the first class.
And here is the code for my addNewWorkouts method in the Workouts class:
-(void)addNewWorkout:(NSMutableArray*)array {
NSMutableArray *temp = [[NSMutableArray alloc] init];
temp = array;
self.workoutList = temp;
[temp release];
}
Here is my "Workout.h"
#import <Foundation/Foundation.h>
#interface Workouts : NSObject {
NSString *workoutName;
NSMutableArray *workoutList;
NSString *description;
int *reps;
int *weights;
int *sets;
}
#property (nonatomic, retain) NSString *workoutName;
#property (nonatomic, retain ) NSString *description;
#property (nonatomic, retain) NSMutableArray *workoutList;
-(void)addNewWorkout:(NSMutableArray*)array;
#end
Before running this code, I get a Warning from Xcode saying that 'Workouts may not respond to 'addNewWorkouts.'
Anyone know what is causing this error? Once I build & run, I click on the Save button and the app crashes with a unrecognized selector sent to instance 0x3b04410 error.
You call [new addNewWorkouts:customWorkout]
when the method's selector is addNewWorkout: (note that there is no plural in the method name)
This will make a bad method call and result in a crash.
Also, there is a problem with the memory management of the addNewWorkout method.
1- NSMutableArray *temp = [[NSMutableArray alloc] init];
2- temp = array;
3- self.workoutList = temp;
4- [temp release];
You allocate a new NSMutableArray on line 1, then lose its reference on line 2 when you replace its pointer by 'array'. The allocation you just made is lost and the program will leak.
Then, on line 4, you send a release message to 'temp' which actually points to 'array', resulting in the release of the parameter that you received and not the temporary object.
Is there a reason whny you create a temporary array? You can just assign the property and make the property copy or retain it, depending on your needs.

How do I removeAllObjects on my NSMutableArray that is part of another object?

I have an object defined like this:
Scores.h:
#interface Scores : NSObject {
NSString *sentenceKey;
NSMutableArray *scorrectAnswers;
}
#property (nonatomic, copy) NSString *sentenceKey;
#property (nonatomic, copy) NSMutableArray *scorrectAnswers;
+ (id)addScore:(NSString *)senKey;
- (id)initWithSentenceKey:(NSString *)sKey
scorrectAnswers:(NSMutableArray *)scorrectAs;
- (id)initWithSentenceKey:(NSString *)sKey;
- (void)removeArrayObjects;
Score.m:
#import "Scores.h"
#implementation Scores
#synthesize sentenceKey, scorrectAnswers;
+ (id)addScore:(NSString *)senKey
{
Scores *newScore = [[self alloc] initWithSentenceKey:senKey
scorrectAnswers:[NSMutableArray new]];
return [newScore autorelease];}
I'm trying to removeAllObjects on my mutable array with this method:
- (void)removeArrayObjects;{
[scorrectAnswers removeAllObjects];}
...which I call from another program like this:
for (Scores *sScore in scores)
{
[sScore removeArrayObjects];
}
... and I get this error when I run it:
-[__NSArrayI removeAllObjects]: unrecognized selector sent to instance 0x53412d0
Can anyone tell me what I'm doing wrong here? Thanks.
You are not dealing with an NSMutableArray as the error indicates you have an immutable NSArray.
This question may be your answer NSMutableArray addObject: -[__NSArrayI addObject:]: unrecognized selector sent to instance
Basically the copy you used when defining your #property will cause the setter to be generated using
scorrectAnswers = [newMutableArray copy];
which returns an immutable NSArray.
You can re-implement this method and change the previous line for:
scorrectAnswers = [newMutableArray mutableCopy];
or use retain instead of copy
This can also occur when getting data from a plist
If you are using a plist it will return an NSArray even if you save an NSMutableArray it will be cast. So when retrieving you will need to do something like:
scorrectAnswers = [[NSMutableArray alloc] initWithArray:[userDefault objectForKey:#"my_array_key"]]
It doesn't look like like the memory pointed to by scorrectAnswers is actually pointing to an NSMutableArray. Where and how do you initialize that variable? If you are setting the ivar directly with an autoreleased object, like:
scorrectAnswers = [NSMutableArray arrayWithCapacity:10];
then the autoreleased array will be destroyed, since you're not retaining it (or copying it). If that memory gets reallocated to point to another object, you'll see an error like the one you're getting, with an unexpected type. If the memory has not been reallocated, you'll get an EXC_BAD_ACCESS error.
Similar to what was mentioned above, I had an NSMutableArray which was being re-allocated somewhere in my code as an NSArray. Once I modified that to correctly be an NSMutableArray, it resolved my problem.
I would suggest doing a quick search to ensure that you have not reallocated the array somewhere in your project and modify accordingly.

Objective-C initializing an NSArray vs NSMutableArray

Why does this work:
self.array = newArray;
But this doesn't:
[[self mutableArray] addObject:object];
Meaning, why do I need to init the NSMutableArray for it to work when I don't have to init the NSArray?
EDIT: Hops this is clearer guys.
Interface:
#interface Foo : UIViewController {
}
#property (nonatomic, retain) NSArray *array;
#property (nonatomic, retain) NSMutableArray *mutableArray;
#end
Implementation:
#implementation Foo
#synthesize array;
#synthesize mutableArray;
- (void)viewDidLoad {
[super viewDidLoad];
self.array = [Class returningAnArray];
[[self mutableArray] addObject:objectIHaveOmittedTheCode];
}
#end
self.array = newArray;
In this line, you are assigning already created object to self.array. So, you've no need to create it.
[[self mutableArray] addObject:object];
But in this line you are trying to add an object to a array which is not created actually. If you don't create the array, it will be nil, and sending message to nil won't take any effect.
In Objective-C NSArray objects are immutable.
self.array = newArray;
This line is a property assignment. The self.array property returns a reference pointing to a location in memory that contains an NSArray object. By assigning the property to different objects you're not really modifying the object themselves.
If you wish to modify an existing NSArray object, you'll have to create a NSMutableArray object containing the same elements:
NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithArray:self.array];
[mutableArray addObject:object];
Note that NSMutableArray inherits from NSArray, so you can safely assign the object referenced by mutableArray to any variable of type NSArray.
[Class returningArray] did the allocation for you. Every object needs to be allocated (and should be initialized) before it can used. The solution is.
- (void)viewDidLoad {
[super viewDidLoad];
self.array = [Class returningAnArray];
self.mutableArray = [NSMutableArray array];
//Now you can use mutable array
[[self mutableArray] addObject:objectIHaveOmittedTheCode];
}
Now you have created your array and your mutable array with out explicitly calling alloc on either because those classes have done it for you.

How to save a NSMutableArray (containing other arrays) to file

This has been asked before and people have given very good instructions on how to do this, e.g. here.
However, I was wondering if I really need to work with NSCoder if I simply wanted to save one NSMutableArray (containing various instances of another NSMutableArray) to a file? I tried this but only got an error message:
-(void)saveLibraryDat {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents directory
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"myLibrary.dat"];
NSError *error;
[myLibrary writeToFile:filePath atomically:YES];
if (error) {
NSLog(#"There was an error saving myLibrary.dat: %#", error);
}
}
My error message:
2011-05-13 22:00:47.840 MoleNotes[15437:207] There was an error saving myLibrary.dat: (
1,
2
)
So I guess I have to work with NSCoder, right? If so, I was wondering how to go about this. People have explained how to do this with a class, but in my case, I have a NSMutableArray (myLibrary) which contains various instances of a class. Will I have to implement the NSCoder in this class and the NSMutableArray?
I alloc my library like this:
myLibrary = [[NSMutableArray alloc] init];
And then add instances of a class called NoteBook.m like this:
NoteBook *newNoteBook = [[NoteBook alloc] init];
newNoteBook.titleName = #"Notes"; // etc.
[myLibrary addObject:newNoteBook];
So where exactly do I put the NSCoder commands? Only into my NoteBook.m class? Will this automatically take care of myLibrary?
Thanks for any suggestions.
EDIT:
So I've updated my code, but I guess the big problem is that my NSMutableArray myLibrary contains several instances of a custom class I've set up (called notebook). I have set up NSCoding for this class (and all its variables) so that I can save it and load it.
Now my app works totally fine if I create the NSMutableArray in the app (i.e. when the app is started for the very first time, no file exists), instead of loading it from disk:
-(void) setupLibrary {
myLibrary = [[NSMutableArray alloc] init];
NoteBook *newNoteBook = [[NoteBook alloc] init];
newNoteBook.titleName = #"Notes";
/...
If I load it from disk, it works fine as well:
-(void)loadLibraryDat {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents directory
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"myLibrary.dat"];
myLibrary = [[NSMutableArray alloc] init];
myLibrary = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
if (!myLibrary) {
// if it couldn't be loaded from disk create a new one
NSLog(#"myLibrary.dat empty... set up new one");
[self setupLibrary];
} else { NSLog(#"Loading myLibrary.dat successful."); }
}
If I log everything which is contained in my library after loading it, everything is still fine. E.g. the following works totally fine:
NSLog(#"%#", [[self.myLibrary objectAtIndex:0] titleName]);
The big problem is, however, if any other method tries to access myLibrary. For instance, if I call the very same log command from another method, the app will crash and I get this error message:
[NSCFString objectAtIndex:]: unrecognized selector sent to instance 0x4b38510
2011-05-14 14:09:10.490 Notes[17091:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSCFString objectAtIndex:]: unrecognized selector sent to instance 0x4b38510'
This sounds to me as if myLibrary has become deallocated somehow, but I can't see why. How could this have happened? I have the feeling that I did something wrong in my NSCoding set up... because if I simply create myLibrary in code, everything works like wonderfully. It's only if I load it from the disk, that the app will crash.
Here is the class setup:
#import <Foundation/Foundation.h>
#interface NoteBook : NSObject <NSCoding> {
NSString *titleName;
NSString *fileName;
NSMutableArray *tabTitles;
NSMutableArray *tabColours;
NSMutableArray *tabReference;
}
#property (nonatomic, retain) NSString *titleName;
#property (nonatomic, retain) NSString *fileName;
#property (nonatomic, retain) NSMutableArray *tabTitles;
#property (nonatomic, retain) NSMutableArray *tabColours;
#property (nonatomic, retain) NSMutableArray *tabReference;
-(id)initWithCoder:(NSCoder *)aDecoder;
-(void)encodeWithCoder:(NSCoder *)aCoder;
#end
//
// NoteBook.m
#import "NoteBook.h"
#implementation NoteBook
#synthesize titleName, fileName, tabTitles, tabColours, tabReference;
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super init];
if (self) {
self.titleName = [aDecoder decodeObjectForKey:#"titleName"];
self.fileName = [aDecoder decodeObjectForKey:#"fileName"];
self.tabTitles = [aDecoder decodeObjectForKey:#"tabTitles"];
self.tabColours = [aDecoder decodeObjectForKey:#"tabColours"];
self.tabReference = [aDecoder decodeObjectForKey:#"tabReference"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:titleName forKey:#"titleName"];
[aCoder encodeObject:fileName forKey:#"fileName"];
[aCoder encodeObject:tabTitles forKey:#"tabTitles"];
[aCoder encodeObject:tabColours forKey:#"tabColours"];
[aCoder encodeObject:tabReference forKey:#"tabReference"];
}
#end
EDIT:
I think I've solved it... I forgot a little 'self'... which messed it all up and deallocated myLibrary:
self.myLibrary = [NSKeyedUnarchiver
unarchiveObjectWithFile:filePath];
if (self.myLibrary == nil) {
NSLog(#"myLibrary.dat empty... set up new one");
[self setupLibrary];
} else { NSLog(#"Loading myLibrary.dat successful."); }
Your code is busted. The "error" variable is uninitialized and never set, so when you check it, you're just seeing random garbage data. If you want to know whether the write was successful, check the return value of writeToFile:atomically:. It will be YES if the write succeeded and NO if it didn't.
However, NSArray's writeTo… methods are for creating plists. If non-property-list objects are in your array, that method isn't appropriate, and an archiver is what you want. Just do something like [[NSKeyedArchiver archivedDataWithRootObject:myLibrary] writeToFile:writeToFile:filePath atomically:YES].
To make your objects conform to NSCoding correctly, just have them implement initWithCoder: and encodeWithCoder:, and in those methods, use NSCoder's storage methods to store the object's instance variables (and the retrieval methods to get them back out).
NSCoder is a protocol that your class must conform to in order to be archived to data/file. Works something like Serealizabe in Java.
Add conformance to the class header like this:
#interface NoteBook : NSObject <NSCoder> { // …
And then you must implement two methods:
-(id)initWithCoder:(NSCoder)decoder;
{
self = [super initWithCoder:decoder];
if (self) {
_someIvar = [decoder decodeObjectForKey:#"someKey"];
// And more init as needed…
}
return self;
}
-(void)encodeWithCoder:(NSCoder)coder;
{
[super encodeWithCoder:coder];
[coder encodeObject:_someIvar forKey#"someKey"];
/// Etc…
}
I would also advice against using -[NSArray writeToFile:atomically:] since in work with property list compliant objects only, not coding compliant classes. The property list object are NSString, NSData, NSArray, or NSDictionary, NSDate, and NSNumber. The list can not be extended.
Instead use NSKeyedArchiver/NSKeyedUnarchiver. Almost as simple to use:
if (![NSKeyedArchive archiveRootObject:yourArrat toFile:path]) {
// It failed.
}