NSMutableArray Add/Remove Objects (Inherited File) - nsmutablearray

Okay, so I'm pretty new to xcode but I cannot find something specific to this issue anywhere. So I declare the array and instantiate it in the following files:
//xmlToUrl.h
#import <Foundation/Foundation.h>
#interface xmlToUrl : NSObject {
NSMutableArray *field;
NSMutableArray *name;
}
#property(nonatomic, retain)NSMutableArray *field;
#property(nonatomic, retain)NSMutableArray *name;
#end
and
//xmlToUrl.m
#import "xmlToUrl.h"
#implementation xmlToUrl
#synthesize field;
#synthesize name;
-(void)dealloc
{
[field release];
[name release];
[super dealloc];
}
#end
So this is where I am confused. I don't know how to correctly "alloc" or "init" the mutable arrays, nor how to handle the add/remove operations from another file which inherits xmlToUrl.h.
The code (in the other file) as I have it now just prints null. Its listed below. What am I doing wrong?!?
//nodeContent is just a NSMutableString
[xmlToUrlObject.name addObject:nodeContent];
NSLog(#"xml Name = %#", xmlToUrlObject.name);
//I omitted all the operational code here but if I NSLog nodeContent it prints the correct values
[xmlToUrlObject.field addObject:nodeContent];
NSLog(#"xml Field = %#", xmlToUrlObject.field);

You need an init function in your implementation file, it would look similar to the following
-(id) init
{
self = [super init];
if (self) {
field = [[NSMutableArray alloc] init];
name = [[NSMutableArray alloc] init];
}
return self;
}
Then whenever you create an instance of your xmlToUrl class via [[xmlToUrl alloc] init] you will have an instance of your class that has already initialized your two NSMutableArrays

Related

Not accessing value from Object

I have a NSObject called GettingHere which has a NSString *content.
I then have a UIViewController on which I create a button programatically as follows (this button working as intended):
byAirButton = [UIButton buttonWithType:UIButtonTypeCustom];
byAirButton.tag = 1;
byAirButton.frame = CGRectMake(25, 140, 280.f, 40.f);
UIImage *airButton = [UIImage imageNamed:#"gettingHereByAirButton.png"];
[byAirButton setBackgroundImage:airButton forState:UIControlStateNormal];
[self.view addSubview:byAirButton];
[byAirButton addTarget:self action:#selector(byAirButtonClicked) forControlEvents:UIControlEventTouchUpInside];
For the action:#selector(byAirButtonClicked), I do the following. gettingHere is an instance of the GettingHere object.
- (void) byAirButtonClicked
{
gettingHere.content = #"This is how to get here by Air";
NSLog(#"Content: %#", gettingHere.content);
[self performSegueWithIdentifier:#"gettingHereSegue" sender:self];
}
The idea is to set the content for my GettingHere object and then just call that from the next view (GettingHereViewController) when the user clicks the byAirButton.
This NSLog shows that content is being set.
In my prepareForSegue, I do the following:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"gettingHereSegue"])
{
NSLog(#"Content to be passed: %#", gettingHere.content);
GettingHereViewController *vc = (GettingHereViewController *)segue.destinationViewController;
vc.gettingHere.content = gettingHere.content;
}
}
The segue works fine, but the NSLog shows my gettingHere object values as being (null).
Can anyone tell me where I am going wrong please? I have stepped through it several times but can't figure out where I am going wrong.
EDIT: Here is how I instantiate the GettingHere Object.
In the SubNavViewController.h
#import "GettingHereContent.h"
#interface SubNavViewController : UIViewController
#property GettingHereContent *gettingHere;
In the SubNavViewController.m
#import "SubNavViewController.h"
#import "GettingHereViewController.h"
#import "GettingHereContent.h"
#interface SubNavViewController ()
#end
#implementation SubNavViewController
#synthesize gettingHere;
And here is how I create the GettingHere Object:
GettingHere.h
#import <Foundation/Foundation.h>
#interface GettingHereContent : NSObject
#property (nonatomic, strong) NSString *content;
#end
GettingHere.m
#import "GettingHereContent.h"
#implementation GettingHereContent
#synthesize content;
#end
You never alloc init your gettingHere property. Try this in your init method of your VC
gettingHere = [[GettingHereContent alloc] init];
Also don't forget to release it: answer from here: alloc + init with synthesized property - does it cause retain count to increase by two?
#interface Foo : Bar {
SomeClass* bla;
}
#property (nonatomic, retain) SomeClass* bla;
#end
#implementation Foo
#synthesize bla;
-(id)init {
...
bla = [[SomeClass alloc] init];
...
}
-(void)dealloc {
[bla release];
...
[super dealloc];
}

How do I access properties of an object when inside another custom object in Xcode / Obj C?

As I newbie I sort of understand how to create and access properties for an object with dot notation.. eg I have an object golfCourse with a property courseName so golfCourse.courseName=#"My Course" works OK. My problem is that if I create a "holeObject" containing Par and Distance and create Hole1, Hole2 etc inside my Course Object trying to access them by golfCourse.Hole1.Par is returning null... My various searches have not found me any clarity.. Can someone point me in the right direction?
Many thanks
HoleObject.h
#import <Foundation/Foundation.h>
#interface HoleObject : NSObject
#property(nonatomic,strong) NSString* par;
#property(nonatomic,weak) NSString* yellowDistance;
#end
HoleObject.m
#import "HoleObject.h"
#implementation HoleObject
#synthesize
par=_par,
yellowDistance=_yellowDistance,
-(void) encodeWithCoder:(NSCoder*)encoder
{
[encoder encodeObject:self.par forKey:#"Par"];
[encoder encodeObject:self.yellowDistance forKey:#"YellowDistance"];
}
-(id) initWithCoder:(NSCoder*)decoder
{
if((self=[super init]))
{
self.par=[decoder decodeObjectForKey:#"Par"];
self.yellowDistance=[decoder decodeObjectForKey:#"YellowDistance"];
}
return self;
}
#end
CourseObject.h
#import <Foundation/Foundation.h>
#import "HoleObject.h"
#interface CourseObject : NSObject
#property(nonatomic,strong)NSString* courseName;
#property(nonatomic,strong)NSString* courseAddress;
#property(nonatomic,strong)HoleObject* hole1;
#property(nonatomic,weak)HoleObject* hole2;
etc...
#end
CourseObject.m
#import "CourseObject.h"
#implementation CourseObject
#synthesize
courseName=_courseName,
courseAddress=_courseAddress,
hole1=_hole1,
etc;
-(void) encodeWithCoder:(NSCoder*)encoder
{
[encoder encodeObject:self.courseName forKey:#"CourseName"];
[encoder encodeObject:self.courseName forKey:#"CourseAddress"];
[encoder encodeObject:self.hole1 forKey:#"Hole1"];
etc;
}
-(id) initWithCoder:(NSCoder*)decoder
{
if((self = [super init]))
{
self.courseName=[decoder decodeObjectForKey:#"CourseName"];
self.courseAddress=[decoder decodeObjectForKey:#"CourseAddress"];
self.hole1 = [decoder decodeObjectForKey:#"Hole1"];
self.hole2 = [decoder decodeObjectForKey:#"Hole2"];
etc;
}
return self;
}
#end
Then in my main View Controller..
- (void)viewDidLoad
{
[super viewDidLoad];
allCourses=[[NSMutableArray alloc] initWithCapacity:2];
CourseObject*thisCourse;
thisCourse=[[CourseObject alloc]init];
thisCourse.courseName=#"Branston";
thisCourse.courseAddress=#"The World";
thisCourse.hole1.par=#"4";
thisCourse.hole1.yellowDistance=#"336";
but if I then try and NSLog thisCourse.hole1.par Im getting null?
Thanks for looking.
Spent some time trying different things with this as it was pretty clear that the Null was showing the object was not being created properly.. Found that [[CourseObject alloc]init] does not actually do anything for the objects "sub-Objects" and I needed to do course.hole1=[[HoleObject alloc] init] for all 18 holes as well... bit fiddly but seems to work..

Appending NSMutableStrings - Exepected "." before "." token error

I'm not sure what I'm doing wrong. I'm thinking its because the NSMutableArray's *name and *field are declared in a different file.
#import <Foundation/Foundation.h>
#interface xmlToUrl : NSObject {
NSString *base_url;
NSMutableArray *field;
NSMutableArray *name;
}
#property(nonatomic,retain)NSString *base_url;
#property(nonatomic, retain)NSMutableArray *field;
#property(nonatomic, retain)NSMutableArray *name;
#end
and
#import "xmlToUrl.h"
#implementation xmlToUrl
#synthesize base_url;
#synthesize field;
#synthesize name;
-(id) init
{
self = [super init];
if (self) {
field = [[NSMutableArray alloc] init];
name = [[NSMutableArray alloc] init];
}
return self;
}
-(void)dealloc
{
[base_url release];
[field release];
[name release];
[super dealloc];
}
#end
The NSMutableArrays are filled in the ViewController class:
//nodeContent is just a NSMutableString being added to the *name and *field NSMutableArrays
if([ending isEqualToString:#"name"]){
if(![nodeContent isEqualToString:#""])
{[xmlToUrlObject.name addObject:nodeContent];}
}
else if([ending isEqualToString:#"field"]){
if(![nodeContent isEqualToString:#""])
{[xmlToUrlObject.field addObject:nodeContent];}
Error = Expected '.' before '.' token. (on the first line of the code below)
What I want for output: *url string contains base_url, urlPart2, and urlPart3 all joined in order.
ex:
base_url = #"www."
urlPart2 = #"mywebsite"
urlPart3 = #".com"
url = #"www.mywebsite.com"
//xmlToUrl is an instance of its own class (.m file) It contains the *name and *field NSMutableArray
//xmlToUrl.h is inherited in this file
NSMutableString *urlPart2 = [xmlToUrl.name objectAtIndex: 0];
[xmlToUrl.name removeObjectAtIndex:0];
NSMutableString *url = [xmlToUrl.base_url stringByAppendingString:urlPart2];
if([xmlToUrl.field count] != 0)
{NSMutableString *urlPart3 = [xmlToUrl.field objectAtIndex: 0];
[xmlToUrl.field removeObjectAtIndex:0}
url = [url stringByAppendingString:urlPart3];
[urlPart2 release];
[urlPart3 release];
You are trying to access a property on a class, and not on the instance:
#interface xmlToUrl : NSObject {
and
NSMutableString *urlPart2 = [xmlToUrl.name objectAtIndex: 0];
You can only access the property on an instance of xmlToUrl, just like you do in the following line of code:
{[xmlToUrlObject.name addObject:nodeContent];}
Here, xmlToUrlObject is an instance, and not the class.

navigationItem not showing on popoverController

The navigationbar is failing to appear, works fine in a UITableView, but fails inside a popoverController
Initiate a popover popoverController in UIViewController
-(IBAction) btnShowMovies:(id) sender {
if (self.popoverController == nil) {
teamAController *movies =
[[teamAController alloc]
initWithNibName:#"teamAController"
bundle:[NSBundle mainBundle]];
UIPopoverController *popover =
[[UIPopoverController alloc] initWithContentViewController:movies];
popover.delegate = self;
[movies release];
self.popoverController = popover;
[popover release];
}
CGRect popoverRect = [self.view convertRect:[btn frame]
fromView:[btn superview]];
popoverRect.size.width = MIN(popoverRect.size.width, 100);
[self.popoverController
presentPopoverFromRect:popoverRect
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionDown
animated:YES];
}
teamAController.h
#interface teamAController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
UITableView *tableView;
NSArray *theArray;
}
#property (nonatomic, retain) NSArray *theArray;
#property (nonatomic, retain) IBOutlet UITableView *tableView;
-(void) createArray;
teamAController.m
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title= #"FooBarExtreme";
self.contentSizeForViewInPopover = CGSizeMake(250.0, 300.0);
[self createArray];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
Everything works, I have lovely table with images etc, correct sized and placed popover just no title bar..... ?
I found the solution/problem by following the tutorial at http://mobiforge.com/designing/story/using-popoverview-ipad-app-development.
Worth noting that I found this the most comprehensive one on creating uiPopoverController with uiNavigationBar elements from UIButtons.
The issue is that the popover itself belongs to the view that calls it. The content is derived from the xlib/view you load into it. But not the titlebar. You call that in the parent view view.
This code is in the main view and is called from the UIButton
// BookMarksViewController is the class that contains the code/xib for the popover's content
// Of overarching importance is creating it as a UITableViewController
if (self.popoverController == nil) {
BookMarksViewController *bookMarksViewController =
[[BookMarksViewController alloc]
initWithNibName:#"BookMarksViewController"
bundle:[NSBundle mainBundle]];
// Here's the rub: because in effect this view is controlling the popover
// we have to assign nav bar stuff here. Sigh.
bookMarksViewController.navigationItem.title = #"Territories";
UINavigationController *navController =
[[UINavigationController alloc]
initWithRootViewController:bookMarksViewController];
bookMarksViewController.contentSizeForViewInPopover = CGSizeMake(320, 400);
UIPopoverController *popover =
[[UIPopoverController alloc]
initWithContentViewController:navController];
popover.delegate = self;
[bookMarksViewController release];
[navController release];
self.popoverController = popover;
[popover release];
}
CGRect sourceRect = [self.view convertRect:[btn frame] fromView:[btn superview]];
[self.popoverController presentPopoverFromRect:sourceRect
inView:self.view permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES];

Memory Management on NSMutableArray

I read some materials about this then I tried to wrote a simple
app but got confused, here is the sample (using cocos2d template):
MySpriteObject class:
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface MySpriteObject : CCNode {
CCSprite *mySprite;
NSString *spriteInfo;
}
#property(nonatomic,retain) CCSprite *mySprite;
#property(nonatomic,retain) NSString *spriteInfo;
#end
#import "MySpriteObject.h"
#implementation MySpriteObject
#synthesize mySprite;
#synthesize spriteInfo;
-(id) init
{
NSLog(#"MySpriteObject init");
if ((self = [super init])) {
self.mySprite = [CCSprite spriteWithFile:#"Icon.png"];
self.spriteInfo = [[[NSString alloc] initWithFormat:#"sprite info"] autorelease];
}
return (self);
}
-(void)dealloc
{
NSLog(#"MySpriteObject dealloc");
[self.spriteInfo release];
[super dealloc];
}
#end
MyObjectManager class:
#import "cocos2d.h"
#import "MySpriteObject.h"
#class MySpriteObject;
#interface MyObjectManager : CCNode {
}
+(MyObjectManager *)sharedMyObjectManager;
-(NSMutableArray *)func1;
-(NSMutableArray *)func2;
#end
#import "MyObjectManager.h"
#import "MySpriteObject.h"
#implementation MyObjectManager
static MyObjectManager *_sharedMyObjectManager = nil;
+(MyObjectManager *)sharedMyObjectManager
{
NSLog(#"MyObjectManager sharedMyObjectManager");
if (!_sharedMyObjectManager) {
if( [ [MyObjectManager class] isEqual:[self class]] )
_sharedMyObjectManager = [[MyObjectManager alloc] init];
else
_sharedMyObjectManager = [[self alloc] init];
}
return _sharedMyObjectManager;
}
-(id)init
{
NSLog(#"MyObjectManager init");
if( (self = [super init]) ) {
}
return self;
}
-(void)dealloc
{
NSLog(#"MyObjectManager dealloc");
[super dealloc];
}
-(NSMutableArray *)func1
{
NSMutableArray *array1 = [[NSMutableArray alloc] init];
array1 = [self func2];
return array1;
}
-(NSMutableArray *)func2;
{
NSMutableArray *array2 = [[NSMutableArray alloc] init];
for (int i = 0; i < 3; i++) {
MySpriteObject *mySpriteObject = [[MySpriteObject alloc] init];
[array2 addObject:mySpriteObject];
//[mySpriteObject release];
}
return array2;
}
#end
And in the "HelloWorldScene.m" init method:
-(id) init
{
if( (self=[super init] )) {
NSMutableArray *array = [[NSMutableArray alloc] init];
array = [[MyObjectManager sharedMyObjectManager] func1];
for (int i = 0; i < array.count; i++) {
MySpriteObject *s = [[MySpriteObject alloc] init];
s = [array objectAtIndex:i];
NSLog(#"%#", s.spriteInfo);
[s release];
}
[array release];
}
return self;
}
The code posted above works fine (at least no crash), but I think there is
memory leak out there.
At first, I had the fun1 fun2 method return the array like this:
return [array1 autorelease];
return [array2 autorelease];
And released the SpriteObject in the func2 methoed as you can see the commented line.
But the app crashed.
Then I uncommented the SpriteObject release line but it still crashed.
Then I deleted the two autorelease in the return statement and it worked
fine.
Can somebody give something suggestion according to the code above???
Thanks in advance.
Oh boy, there are multiple problems. At first remember to release everything you called "alloc, new, retain, copy" upon. See Objective C release, autorelease, and data types and Release, Dealloc, and the Self reference
The basic problem here is, that you are overwriting previously created variables. For example:
NSMutableArray *array = [[NSMutableArray alloc] init];
array = ... ;
[array release];
Therefore you create a memory leak and get double release trouble. See obj-c NSString and alloc / retain / release for how to do it right.

Resources