Currently developing my first Native iPhone application, the application is going to be integrating within an existing .net application and will be using webServices. However the problem i am facing i believe is nothing more than my understanding of xcode.
I hope i can explain this...
OK within my first view, within the viewDidLoad i go off to the webservice and return my list of items (these populate the tableview) this works completely fine:
--- snippet ---
- (void)viewDidLoad {
//GET ALL ITEMS
myArray = [[NSMutableArray alloc] init];
MyWebService *webService = [[MyWebService alloc] init];
myArray = [webService getAllNewsFunction];
[super viewDidLoad];
}
--- snippet ---
Ok so i now have my tableview populated and awaiting for you to select your item (in this case a news article) i need to determine the selectedItem in order to populate the next view with the details of the article. However it appears that within the didSelectRowAtIndexPath method my array list is no longer accessible. I am very confused at this point due to if i simply create a list of items within my viewDidLoad within the current view without using my webservice for example:
--- snippet ---
// listOfItems = [[NSMutableArray alloc] init];
// [myArray addObject:#"Iceland"];
// [listOfItems addObject:#"Greenland"];
// [listOfItems addObject:#"Switzerland"];
// [listOfItems addObject:#"Norway"];
// [listOfItems addObject:#"New Zealand"];
// [listOfItems addObject:#"Greece"];
// [listOfItems addObject:#"Italy"];
// [listOfItems addObject:#"Ireland"];
--- snippet ---
the above is accessible within didSelectRowAtIndexPath and i can populate the detailview.
Can you please help me pinpoint the problem i am facing and how this can be solved. I understand i have given you the very basics so if i need to provide more information i am happy to do so.
-- update --
ok based on your response i have update the following.
I have now declared myArray as a property
#property (nonatomic, retain) NSMutableArray *myArray;
and also updated the line to:
self.myArray = [webService getAllNewsFunction];
-- update --
however i now receive an error "program received signal: "SIGABRT"" on the self.myArray line.
any ideas?
Thanks Again
If you are following naming conventions then the method [webService getAllNewsFunction] will return an autoreleased array. Therefore when you come to access it again it will most likely have been released already.
If you have used a #property to declare myArray (which you should to save yourself from these problems) then you can resolve this by doing:
self.myArray = [webService getAllNewsFunction];
This line:
myArray = [[NSMutableArray alloc] init];
is also superflous and causing a memory leak as you are reassigning the value of myArray to [webService getAllNewsFunction] immediately after without releasing the new NSMutableArray you alloc/init'd
UPDATE
So from reading your update I think you need to firstly look at the warnings your project now has which will probably read something like:
Property 'myArray' requires method 'setMyArray' to be defined - use #synthesize, #dynamic or provide a method implementation in ...
The next clue to the problem appears in the console I get something like this
-[TestAppDelegate setMyArray:]: unrecognized selector sent to instance ...
So what it all boils down to is you either need to provide the methods
- (NSMutableArray *)myArray;
- (void)setMyArray:(NSMutableArray *)myArray;
or let the compiler do it for you by adding a #synthesize statement like this
.m
#implementation YourClass
#synthesize myArray;
// The rest of your class methods
- (void)dealloc
{
// release other ivars
[myArray release];
[super dealloc];
}
The synthesize is the easier, quicker options and the compiler will arrange for the coorect memory management depending on which options you use in your #property declaration.
Related
Basically what i am trying to do is make a network refresh and fetch objects, store it in a nsmutable array in my app delegate. Then i have a listviewController which uses that mutable array to display data.
Setting nsarray is not working here is the code:
//Appdelegate code called after pulldown to refresh is done on listview:
[ListView setArrayElements:(NSMutableArray*)sortedArray ];
NSLog(#"sortedArray count:%d",sortedArray);
NSLog(#"ListView Array count:%d",[ListView.ArrayElements count]);
Result i get in log : "sortedArray count:12" (which is perfect)&"ListView Array count:0" (this is not the right result)
It's hard to assume without seeing more of your code but how do you define the ArrayElements property? It may not be retaining itself and you may not have initialized it when the ListView object is created.
Let me know if this works;
Make sure ArrayElements is created in your ListView.h like the following:
#property (nonatomic, retain) NSMutableArray *ArrayElements;
Or on -init or -viewDidLoad of your ListView,
self.ArrayElements = [[NSMutableArray alloc] init];
Don't forget to release what you retained:
- (void)dealloc
{
//.....
[ArrayElements release];
[super dealloc];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.mTableView reloadData];
}
use this method
Do not make the UITableView object as a property. Just use tableView object , remove 'self.' portion.
Tell me if it helps!
I am developing an iPhone app and I have a problem accessing to one NSArray defined on delegate.
My app has two tabs. These two tabs have an UITableView. I have the source of the data of these tables on one NSArray defined in the delegate.
When I load the application, the first tab loads correctly all the content. This is one part of code of the first tab controller:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
mainAppDelegate *delegate = [[UIApplication sharedApplication]delegate];
return [delegate.dataArray count];
}
When the debugger is on return statement, I can see that dataArray has 9 elements. The code works fine.
When I click on the second tab, the same code is executed in the second's tab controller. But while debugger is on return statement, I can see that delegate is not null and dataArray shows
{(int)[$VAR count]} objects
On next step, program crashes giving EXC_BAD_ACCESS
I think in this point dataArray has been released, but I don't know when. I have deleted dataArray release calls on dealloc functions.
This is the property definition of dataArray:
#property (nonatomic, retain) NSArray *dataArray;
Anyone has any idea? I'm completely lost on it. Thanks for your help!
As per your comment, you initialize your array like this:
dataArray = [dict objectForKey:#"data"];
This does not retain the array since you are accessing the ivar directly, not the property. You should do this instead:
self.dataArray = [dict objectForKey:#"data"];
Some programmers prefer to synthesize their properties with a different ivar name to avoid such mistakes.
#synthesize dataArray = dataArray_;
In your comments you just said that dataArray is the response of a servlet and you're parsing it with json-framework.
This sounds like your dataArray object just stores a reference to an external array object being passed in.
You haven't posted much code. Could you show where your dict object is initialized?
Your external object might be getting released causing an EXC_BAD_ACCESS
So I'm having trouble with OOAD, properties, the self keyword, etc. I wanted to just create a simple test project that has a UITableView. I have an ivar of
NSArray *tableData;
how would I write a setter and getter method for this? I thought my setter would look like:
- (void)setTableData:(NSArray *)array {
[tableData autorelease];
tableData = [array retain];
}
Then when I try to use this method in my viewDidLoad, I realize that I need to create an instance of my ViewController. This seems like what not to do when I look at how it's done in books where they create a property for the NSArray, then in viewDidLoad just do a
NSArray *array = [[NSArray alloc] initWithObjects:#"1", #"2", #"3", #"4", nil];
self.tableData = array;
[array release];
I'm kind of just trying to understand what goes on behind the scenes, to try to understand OOAD principles, ivars, properties, self, etc. Thanks in advance.
I'm sure you already know that using #synthesize will create setter/getter methods for you, but it's good to know what's going on "under the hood" to understand the concepts.
As far as a setter method goes, you're probably better off with something like this:
- (void)setTableData:(NSArray *)array {
if (tableData != array) {
[tableData release];
tableData = [array retain];
}
}
This basically checks to make sure the new array is actually different than the current. If it is, it releases the old instance and sets the new one.
For a getter method, just use:
- (NSArray *)tableData (
return tableData;
}
This can be accessed by calling self.tableData. And of course setting the array is done just as you have done, with self.tableData = array;
I hope that helps. If you need more information, just say so and I'll be happy to try and explain further
I'm getting this error when trying to see the contents of a NSMutableArray:
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00000021
0x94d5a688 in objc_msgSend ()
ViewController.h:
#interface PeopleViewController : UITableViewController {
NSMutableArray *people;
}
#property (nonatomic, retain) NSMutableArray *people;
ViewController.m:
#implementation PeopleViewController
#synthesize people;
In viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
// initialize our people array with an autoreleased object
people = [NSMutableArray array];
... Populate the people array with Person objects.
}
When I'm at the point where I'm modifying the contents of a cell in the tableview, I'm unable to access the people array in gdb when typing 'po self.people':
Person *person = [[Person alloc] init];
person = [self.people objectAtIndex: indexPath.row]; // <--- 'po self.people' called
cell.textLabel.text = person.personName;
Any ideas why I can't access it?
The line
people = [NSMutableArray array];
returns an autoreleased array that will be released on the next iteration of the current run loop. You should retain that:
people = [[NSMutableArray array] retain];
and of course release it in your dealloc method.
However: Apple engineers have often mentioned in conferences to avoid autoreleased instances like this whenever possible in the iPhone, for performance reasons. Try using alloc/init instead:
people = [[NSMutableArray alloc] initWithCapacity:1];
with the corresponding release in the dealloc method. In this case you don't even need to retain (init returns an instance with a retain count of 1, which is what you need).
And justin's comment is correct: you should do this instead:
Person *person = [people objectAtIndex:indexPath.row];
cell.textLabel.text = person.personName;
and this should work.
is indexPath.row > [people count]?
Also, why are you doing this:
Person *person = [[Person alloc] init]
You're allocating memory, and then pointing to completely different memory.
You can avoid having to fuss with retaining properties by using the self notation to call the accessor and setter methods created by the #synthesize directive.
When you set the people property directly in viewDidLoad it sets the property but does nothing for memory management. However, if you set it with self.people you actually call the synthesized setter method that because of the retain setting of the #property directive will automatically retain the assigned array.
As an aside, I would recommend always using -[NSMutableArray initWithCapacity:] instead of a bare init. It is the actual initializer for the class. You can call it with just '1' if you don't know how big it will be. In the past, I have seen odd problem arise from just using bare init.
I have an NSMutableArray as a member variable for a class.
In the .h file:
#interface bleh {
NSMutableArray *list;
}
#property (readonly, assign) NSMutableArray *list;
#end
In the .m file:
#implementation bleh
#synthesize list;
-(void)init;
{
list = [NSMutableArray arrayWithCapacity:30];
}
#end
Now, I'm not really an objective-C programmer, so maybe I'm missing some of the nuances, but when I do the following:
NSMutableString *listItem = [NSMutableString stringWithString:#"Foobar"];
[list addObject:listItem];
I'm getting strange behavior. Namely, I'm using this to keep a list of files that I eventually want to attach to an email and then open the picker. I'm getting a SIGABRT, and upon debugging, I find out that whenever I operate on list, I'm getting nothing. addObject messages don't increase the size of the NSMutableArray at all.
Am I missing something? Can someone show me a full implementation of setting up an NSMutableArray to be manipulated within a class in Objective C?
Thanks.
PS - Assume that I'm smart enough to put the manipulations of the NSMutableArray inside of a member function for the class containing the member variable.
in the latest release of the SDK arrayWithCapacity is bad practice.
but in your code you creating a array that no one is owner , clam your array properly.
don't forget initialize your array
NSMutableArray *array = [[NSMutableArray alloc] init];
fix the (readonly,assign),
How are you actually creating your array? Is it possible that it's being autoreleased and going away? Remember, if you create it with a convenience method (like array or something) you need to retain it.
You're creating the array with arrayWithCapacity:, which returns an array you don't own, and you're never claiming ownership over it. Use a property accessor to retain the array:
self.list = [NSMutableArray arrayWithCapacity:30];
I would recommend reading the Cocoa memory management docs. Once you know the rules in there, it will be clear what to do in this sort of situation. They're not very hard, but they are very necessary if you're going to be programming Cocoa.
Your list variable has been auto-released and de-allocated, therefore your program crashes when you try to access it.
There are two ways to create objects in Cocoa:
NSMutableArray* array1 = [[NSMutableArray alloc] initWithCapacity:10];
NSMutableArray* array2 = [NSMutableArray arrayWithCapacity:10];
array1 was created using alloc+init, therefore you own it. It will stick around until you release it.
array2 was not created using alloc+init, therefore you do not own it. You're not responsible for releasing it, but it will go away on its own. You must retain array2 if you want it to stick around.
Your list property declaration is keeping you from properly retaining the NSMutableArray. By calling arrayWithCapacity you're effectively putting the array in an autorelease pool, which means it could be deallocated at any time if no object interested in keeping it around. While you are, the way you have things declared doesn't reflect that:
#property (readonly, assign) NSMutableArray *list;
The above declaration simply sets this pointer to be a copy of another pointer - it does no memory management for you. Instead it should read:
#property (readonly, retain) NSMutableArray *list;
... and you should assign the list like so:
self.list = [NSMutableArray arrayWithCapacity:64];
Because you specify the retain attribute for the property, whenever it is assigned a new value the retain message will be sent to that new value, communicating to the memory manager that you don't want this object deallocated. In order to bring this full circle, you'll need to release the object when you containing class is deallocated:
- (void)dealloc
{
[list release];
[super dealloc];
}
Are you initializing your list properly? Ie do you have something like the following in your code?
list = [[NSMutableArray alloc] init];
Problem ehre (assuming you initing your array properly) could be that #"Foobar" assings an NSString not an NSMutableString so its failing because if distinct types you should do
NSMutableString *listItem = [NSMutableString stringWithString:#"Foobar"];
[list addObject:listItem];
or
NSString *listItem =#"FooBar";
[list addObject:listItem];
It doesn't look as though you've actually initialized the NSMutableArray.
In the init event of the object, just say
[self setList:[[NSMutableArray alloc] initWithCapacity:10]]];
(I would just say init, but I don't remember if that works. It doesn't matter what capacity you start with)
Before actually allocating the array, the variable "list" will have a value of nil.