i've been dancing with a tambourine for a while, but still don't know what's the reason for that error.
I've got a tableView with history of user queries data from sqlite base. I'm new to iPhone developing, so my code may be a bit excessive. The hierarchy is:
HistoryModel
model-object with some init methods
HistoryDataController
gets data from database and presents an array of HistoryModel objects
HistoryViewController
subclass of UITableView, displays data
AppDelegate
there i initially store an array of HistoryModel objects (by getting it from HistoryDataController) for HistoryViewController to access it.
The problem is, when i scroll the table or open the tab with it for the second time - it crashes with -[CFString retain]: message sent to deallocated instance
Code:
HistoryModel.h
pretty unnecessary class for that case, but i want that worked to repeat in several identical cases, but a bit more complicated
#interface HistoryModel : NSObject {
int entry_id;
NSString *word;
}
- (id)initWithWord:(NSString *)word;
- (id)initWithWord:(NSString *)word andId:(int)entry_id;
#property int entry_id;
#property (retain) NSString *word;
#end
HistoryModel.m
#implementation HistoryModel
#synthesize entry_id, word;
- (id)initWithWord:(NSString *)_word {
[super init];
word = _word;
return self;
}
- (id)initWithWord:(NSString *)_word andId:(int)_entry_id {
entry_id = _entry_id;
return [self initWithWord:_word];
#end
HistoryDataController.h
i use the entity of that class as getter of data and a storage for HistoryModel objects (in historyEntries property)
#interface HistoryDataController : NSObject {
NSMutableArray *historyEntries;
int limit;
}
#property (nonatomic, retain) NSMutableArray *historyEntries;
#property int limit;
- (id)initWithHistoryData;
- (id)initWithHistoryDataLimitedBy:(int)limit;
HistoryDataController.m
#implementation HistoryDataController
#synthesize historyEntries, limit;
- (id)initWithHistoryDataLimitedBy:(int)_limit {
[super init];
// Getting data from database
{some DB stuff}
NSMutableArray *tmp_historyEntries = [[NSMutableArray alloc] init];
while(result == SQLITE_ROW)
{
HistoryModel *currentHistoryEntry = [[HistoryModel alloc] initWithWord:[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 1)] ];
[tmp_historyEntries addObject:currentHistoryEntry];
result = sqlite3_step(statement);
}
historyEntries = tmp_historyEntries;
{some DB stuff}
return self;
}
#end
HistoryViewController.h
subclass of UITableViewController, gets data stored in AppDelegate's property and displays in the table
#interface HistoryViewController : UITableViewController {
IBOutlet UITableView *historyTable;
SynonymsAppDelegate *appDelegate;
}
#property (retain) UITableView *historyTable;
#end
HistoryViewController.m
#implementation HistoryViewController
#synthesize historyTable, historyEntriesToShow;
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
appDelegate = (SynonymsAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate initHistoryList];
[self.tableView reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
{standart cell stuff}
HistoryModel *historyEntry = [appDelegate.historyList objectAtIndex:indexPath.row];
cell.textLabel.text = historyEntry.word;
return cell;
}
#end
SynonymsAppDelegate.h
when history tab opens, it gets data of historyList property, that was formed by HistoryDataController :)
#interface SynonymsAppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate> {
...
NSMutableArray *historyList;
}
...
#property (retain) NSMutableArray *historyList;
- (void)initHistoryList;
#end
SynonymsAppDelegate.m
#implementation SynonymsAppDelegate
#synthesize window, tabBarController, historyList;
- (void)initHistoryList {
HistoryDataController *historyDataController = [[HistoryDataController alloc] initWithHistoryData];
historyList = historyDataController.historyEntries;
}
#end
Fuf. Sorry for so much code, but i believe that's all necessary.
As a result of half the day spent on this question, i may guess, that problem is somehow connected with HistoryModel entity, because when i delete "retain" for word #property, the error switches for -[CFString isEqualToString:]: message sent to deallocated instance
I'm not really experienced in memory management, but i guess this HistoryModel objects inside historyEntry in HistoryViewController or in historyList in AppDelegate releases somehow, when scrolling the table or opening the tab for the second time.
But this's just my guessing.
Really appreciate the help.
You definitely have an issue in your -[HistoryModel initWithWord] You should retain (or better yet copy) the string that is being passed.
I would write it like this:
- (id)initWithWord:(NSString *)_word {
[super init];
self.word = _word; // this is same as [self setWord:_word]
return self;
}
There are some who would say using the setter in your init is not a good practice. I'm not of that camp. But in any case, you need to be retaining or copying that string.
Then you have a similar issue in your app delegate where you are leaking each HistoryDataController as you create a new one. (and that happens every time that tableview appears). And you really should be retaining that array as well (although that hasn't caused a problem yet because you're leaking the HistoryDataControllers and therefore masking that issue so far.)
My general advice to you would be don't put off memory management. To come back later and try to get it right is complicated and error-prone even for an experienced developer. It is much, much easier to build the correct memory management techniques into the code as you write it. This means it's well worth your time to read the memory management guide first before you start coding something like this. You'll save yourself a lot of time and frustration.
Related
I have been working on this problem for close to 4 days now.
I am at the point where I think its not so much a problem with my code, but the structure of my application that is causing the issue.
I am trying to implement protocols and delegates to get an array from one NSObject(class) to a ViewController.
my code is pretty much line by line copied from this tutorial the only differences are in the face I have ARC turned on so have had to replace (nonatomic, retain) to (strong) and have not used dealloc :)
so with that being said its still not passing the data back to the viewcontroller. (highly annoying) I have tried dozens of different combinations of solutions that I have had help with and nothing has worked. This has lead me to believe that maybe there is an error in the structure of my application or the way things have been initialized etc, which I will attempt to explain now.
When my viewcontroller with tableview loads the viewdidload method called the delegate of my parser class, then once the first cell of the tableview has loaded it called my connection class and tells it to download some data from the server.
Inside my connection class I use NSURLConnection delegates from the apple library, in the delegate method connectionDidFinishLoading the data that has been downloaded is passed over to my parser class (however this is where i think its going wrong because i declare the object again.. which i think is where things are going amiss)
this is how I call my parser class from my connection class.
parserClass *myparser = [[EngineResponses alloc] init];
[myparser ReciveResponse:receivedData];
then once the data is in my parser class it gets parsed and then I try to pass the data across to my viewcontroller.. but its never accessing that delegate method that I set up.
Hopefully this is where the problem is because I just dont know where else I am going wrong.
what do you think?
UPDATE: heres my code -
ViewController.h
#import "EngineResponses.h" //delegates & protocols
interface SearchViewController : UITableViewController <PassParsedData> {
//delegates to parser class
EngineResponses *engineResponses;
//..
ViewController.m
#import "EngineResponses.h"
//this is where I set up the delegate/protocol for the parser class
- (void)viewDidLoad
{
[super viewDidLoad];
//..
engineResponses = [[EngineResponses alloc] init];
[engineResponses setMydelegate:self];
//..
}
//this is where i set up and call the connection class
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//..
if(indexPath.section == 0){
//..
if (indexPath.row == 0){
EngineRequests *engineRequests = [[EngineRequests alloc] init];
[engineRequests initalizePacketVariables:0 startCode:#"myReg" activationCode:#"myAct" methodName:#"GetStuff"];
//..
}
#pragma - Reciver methods
- (void)sendArray:(NSArray *)array
{
ICMfgFilterArray = array;
[self.tableView reloadData];
}
EngineRequests.m
//connection delegates etc..
//then I pass the data from the connection delegates over to the parser class
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
EngineResponses *engineResponses = [[EngineResponses alloc] init];
[engineResponses ReciveResponse:receivedData];
}
EngineResponses.h
#protocol PassParsedData
- (void)sendArray:(NSArray *)array;
#end
//..
id <PassParsedData> mydelegate;
//..
#property (strong) id <PassParsedData> mydelegate;
EngineResponses.m
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
//..
[[self mydelegate]sendArray:filteredArray];
}
1
Allright. I will re-do it based on your updated code. To make it easy I copy your code and do the amendments.
ViewController.h
#import "EngineResponses.h" //delegates & protocols
interface SearchViewController : UITableViewController <PassParsedData> {
//delegates to parser class
EngineResponses *engineResponses;
EngineRequests *engineRequests;
//..
Explanation:
You are using ARC. If you define the pointer locally, as you did before, and to not
retain it - which you can't because of ARC - then it will be released directly after its
creation. You will have to keep at least one reference to the object.
Bare in mind that ARC means Automatic Reference Counting. As soon as there is no
reference to an object it will be released.
This proposal with the engineRequests object defined here only works while you
submit only one request at a time. If you have several requests, i.e. for more than one cell or
whatver, then you may go for a mutable array or mutable dictionary where you keep the requests while you use them.
ViewController.m
#import "EngineResponses.h"
//this is where I set up the delegate/protocol for the parser class
- (void)viewDidLoad
{
[super viewDidLoad];
//..
engineResponses = [[EngineResponses alloc] init];
[engineResponses setMydelegate:self];
engineRequests = [[EngineRequests alloc] init]; // Use instance variable instead of local variable
[engineRequests setEnineResponses:engineResponses];
//..
}
//this is where i set up and call the connection class
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//..
if(indexPath.section == 0){
//..
if (indexPath.row == 0){
[engineRequests initalizePacketVariables:0 startCode:#"myReg" activationCode:#"myAct" methodName:#"GetStuff"];
//..
}
#pragma - Reciver methods
- (void)sendArray:(NSArray *)array
{
ICMfgFilterArray = array;
[self.tableView reloadData];
}
Explanation: The engineRequets is now an instance varaible and should not be re-defined locally.
You could define a variable of the same name locally which would hide the instance variable. I think
in that case you get a compiler warning but that will work and will most probably confuse you.
Again, if you use more than one request at a time then this solution will not work!
EngineRequests.h
EngineResponses *engineResponses;
EngineRequests.m
#synthesize engineResponses;
//connection delegates etc..
//then I pass the data from the connection delegates over to the parser class
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//EngineResponses *engineResponses = [[EngineResponses alloc] init]; //This Object has already been created!
[engineResponses ReciveResponse:receivedData];
}
Explanation: Here, too, the reference to EngineResponses is now an instance variable, not a locally defined one. The object will not be newly created but it references to that very object that was created in the view controller. That is the one EngineResponses that 'knows' its view controller object and can therefore pass back the parsed data.
EngineResponses.h
#protocol PassParsedData
- (void)sendArray:(NSArray *)array;
#end
//..
id <PassParsedData> mydelegate;
//..
#property (strong) id <PassParsedData> mydelegate;
EngineResponses.m
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
//..
[[self mydelegate]sendArray:filteredArray];
}
... give it a try :)
Always check for nil objects. Sending a message to a nil object will do nothing and your app will continue. I bet this is the problem since you are locally allocing all over the place. Why dont you make the receivedata method a static method instead since it looks like you dont need these classes for more than a few moments for some calculations and parsing. Then nil objects wont be a factor.
MOST NEW TESTING:
I placed a NSLog(#"%p", self.myArray);
after the array assignment and I am seeing a address actually logged.....!?!?!
2012-03-06 01:33:52.618 ArrayTest[9883:f803] 0xae0f160
Seems that Xcode is all wacked out if it cant see the addess of that ivar in either local variables or with the tool tip highlight method...
Thoughts?
NEWEST TESTING:
I created a brand new project.
It seems that simple assigning of objects to ivars is not working at all. If I look at the address of myArray after the assignment of the newly created array it has a null address.
output of nslog
2012-03-06 01:30:37.283 ArrayTest[9848:f803] (
)
(lldb)
//
// ViewController.h
// ArrayTest
//
// Created by Ben J Brown on 3/6/12.
// Copyright (c) 2012StudioBflat. All rights reserved.
//
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
{
NSMutableArray *myArray;
}
#property (strong) NSMutableArray *myArray;
#end
//
// ViewController.m
// ArrayTest
//
// Created by Ben J Brown on 3/6/12.
// Copyright (c) 2012 StudioBflat. All rights reserved.
//
#import "ViewController.h"
#implementation ViewController
#synthesize myArray;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSMutableArray *array = [NSMutableArray arrayWithCapacity:16];
self.myArray = array;
NSLog(#"%#",self.myArray);
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
} else {
return YES;
}
}
#end
OLDER DATA:
In my viewDidLoad I have:
NSLog(#"%#",self.collectionOfImageViews);
self.collectionOfImageViews = [[NSMutableArray alloc] initWithCapacity:NUMBER_OF_COLUMNS*NUMBER_OF_ROWS];
NSLog(#"%#",self.collectionOfImageViews);
However later on when I access that array the array has an address but all the objects that I added to it are gone, and when I send a count message to that object(the NSMutableArray) it throws this in the console:
-[UIImage count]: unrecognized selector sent to instance 0x6b7ab40
My properties in my interface:
#property(strong) NSMutableArray* collectionOfImageViews;
and I have #synthesize collectionOfImageViews; right after my #implmentation... what am I missing here?
Here is where I make the collection:
NSLog(#"%#",self.collectionOfImageViews);
self.collectionOfImageViews = [[NSMutableArray alloc] initWithCapacity:NUMBER_OF_COLUMNS*NUMBER_OF_ROWS];
NSLog(#"%#",self.collectionOfImageViews);
looking at the array it has a null address right after this action....
Concerning that earlier weird error where I had it consoling out that it was a UIImage not responding to count... I fixed that kinda by changing the order of the ivar declarations in the interface:
#import <UIKit/UIKit.h>
#import "TiledImageView.h"
#interface ViewController : UIViewController <TiledImageViewDelegation>
{
NSMutableArray *collectionOfImageViews;
UIImage *sourceImage;
UIImageView *currentTappedView;
}
#property(strong) NSMutableArray* collectionOfImageViews;
#property(strong) UIImage* sourceImage;
#property(strong) UIImageView* currentTappedView;
#end
As for where I fill the mutable array later here is that code:
iView = [[TiledImageView alloc] initWithImage:[UIImage imageWithCGImage:tempImage]];
iView.userInteractionEnabled = YES;
iView.delegate = self;
iView.contentMode = UIViewContentModeScaleAspectFit;
[iView setTag:index];
[iView setPosX:column];
[iView setPosY:row];
[collectionOfImageViews addObject:iView];
I'm pretty darnd confused because this is simple ivar setting and getting.. and alloc and initialization... something I have done many times before but it seems my ivars are not staying alive... I'm new to ARC.
This seems to be an LLDB bug. Use GDB for debugging instead.
edit: It obviously is a bug within lldb, i have filed a bug report back in march (it was marked as a duplicate of another bug which was later marked as closed) - the issue has been resolved in newer Xcode versions.
The fact that u get () means that there is nothing wrong with the array. You can test it easily by adding any other object like an NSNumber and then logging the array again, you should see your object there. About the memory address, If you are using the debugger you should set the break point AFTER the instruction where the array is allocated, then you will be able to see the contents of the array. Otherwise if your break point is not there who knows what you will be seeing.
Finally the -[UIImage count]: unrecognized selector sent to instance 0x6b7ab40
Means you are trying to make an UIImage object perform a count method, which doesn't exist, You probably want the count on the array not the object inside. So the problem is in where you are calling this method, you seem to have a hard time when it comes to referencing either the object or the ivar, to avoid this, on the synthesize change the #synthesize collectionOfImageViews; to #synthesize collectionOfImageViews = collectionOfImageViews;
Also try changing the compiler like others have suggested.
I am passing an NSDictionary object from one view class to another as I transition from a table view to a normal view to show details:
Passing Controller:
[tweetController setTweet:tweet];
Receiving Controller.h:
#interface TweetViewController : UIViewController {
NSDictionary *tweet;
}
#property (nonatomic, retain) NSDictionary *tweet;
Receiving Controller.m:
#implementation TweetViewController
#synthesize tweet = _tweet;
I then try to use this information to set the properties of some fields in my view:
- (void)viewDidLoad
{
[super viewDidLoad];
tweetLabel.text = [_tweet objectForKey:#"text"];
}
The result is a blank label and if I inspect the value of _tweet at this stage it is nil.
I originally had a method which set the value of tweet which I called at the same location as I am now setting the value. If I inspected the value at this stage it was fine.
I presume that the automagic setter through #synthasize is working, but somewhere else the value is being lost.
Sorry this is my first objective C anything! Thanks for any help in advance.
You are using your "tweet" instance variable, whereas the "tweet" property is synthesized to the "_tweet" variable.
You are probably calling the setTweet method after viewDidLoad executes.
I usually pass this kind of thing into a custom init method.
Alternatively, you could do the set before pushing the detail VC onto the nav stack.
Are you sure that tweetLabel isn't nil?
I've made a few corrections & optimisations to your code. You don't need to declare ivars in the header file anymore, they are generated automatically by #synthesize
- (void)dealloc; is only needed if you're not using ARC.
//.h
#interface TweetViewController : UIViewController
#property (strong, nonatomic) NSDictionary *tweet;
#property (strong, nonatomic) IBOutlet UILabel *tweetLabel
#end
//.m
#implementation TweetViewController
#synthesize tweet = _tweet;
#synthesize tweetLabel = _tweetLabel;
- (void)viewDidLoad {
[super viewDidLoad];
self.tweetLabel.text = [self.tweet objectForKey:#"text"];
}
- (void)dealloc {
[_tweet release];
[_tweetLabel release];
[super dealloc];
}
#end
Note: strong is equivalent to retain
To expand on #Rayfleck's answer, since you are new to Objective-C, your custom init method could look like this:
In TweetViewController.h:
- (id)initWithTweet:(NSDictionary*)tweet;
In TweetViewController.m:
- (id)initWithTweet:(NSDictionary*)tweet
{
self = [super init];
if (self) {
_tweet = tweet;
}
return self;
}
and then in your passing controller you'd allocate and initialize like this:
TweetViewController *tvc = [[TweetViewController alloc] initWithTweet:myTweet];
I have too much code to know which i need to quote here, but in my app delegate I have an NSMutableArray. Then in another class, it creates a new entry to the NSMutableArray but upon passing back to another class which should use that to display something on screen, it doesn't display anything. Putting an NSLog for the NSMutableArray count at the end of the class creating it displays the number 1, and then putting the same NSLog code at the start of the class which is meant to use that returns 0.
Any ideas why this is?
EDIT: Ok, i'll try and include all related code..
app delegate.h:
#interface palettesAppDelegate : NSObject <UIApplicationDelegate> {
NSMutableArray *colourPalettesContainer;
}
#property (assign, readwrite) NSMutableArray *colourPalettesContainer;
#end
app delegate.m:
#import "palettesAppDelegate.h"
#implementation palettesAppDelegate
#synthesize colourPalettesContainer;
- (void)dealloc {
[colourPalettesContainer release];
[super dealloc];
}
#end
Homeview.h:
#import <UIKit/UIKit.h>
#import "HandlingPalettes.h"
#interface HomeView : UIViewController {
HandlingPalettes *handlingPalettes;
}
#end
Homeview.m:
#import "HomeView.h"
#import <QuartzCore/QuartzCore.h>
#implementation HomeView
- (void)viewDidLoad {
[super viewDidLoad];
handlingPalettes = [[HandlingPalettes alloc] init];
[handlingPalettes newPalette];
}
-(void)viewWillAppear:(BOOL)animated {
NSLog(#"view will appear: %i", [dataCenter.colourPalettesContainer count]);
int numberOfExisting = [dataCenter.colourPalettesContainer count];
}
- (void)dealloc {
[handlingPalettes release];
[super dealloc];
}
#end
HandlingPalettes.h:
#import <UIKit/UIKit.h>
#interface HandlingPalettes : UIViewController {
}
-(void)newPalette;
#end
HandlingPalettes.m:
#import "HandlingPalettes.h"
#import "HomeView.h"
#import "palettesAppDelegate.h"
#implementation HandlingPalettes
-(void)newPalette {
palettesAppDelegate *dataCenter = (palettesAppDelegate *)[[UIApplication sharedApplication] delegate];
//If this is the first palette
if (dataCenter.colourPalettesContainer == nil) {
dataCenter.colourPalettesContainer = [[NSMutableArray alloc] init];
}
//Add a new palette
[dataCenter.colourPalettesContainer addObject:#"Test1", #"Test2", nil];
NSLog(#"Handling: %i", [dataCenter.colourPalettesContainer count]);
}- (void)dealloc {
[super dealloc];
}
#end
Your main mutablearray is in your app delegate. So, see what happens if in EVERY METHOD that you want to access the array you have the line to set up the app delegate relationship
palettesAppDelegate *dataCenter = (palettesAppDelegate *)[[UIApplication sharedApplication] delegate];
Now, when you call the dataCenter object you will be referencing the App Delegate and your program will find the array.
You may also find that you will need to have an #import "palettesAppDelegate.h" in each object that is going to reference the App Delegate.
Note, just adding the app delegate code is not necessarily the proper way to deal with this issue from an architectural standpoint. But if it works you at least know the answer to your original question.
I suspect the problem is ultimately related to confused memory management of the colourPalettesContainer member. You release it in the app delegate's dealloc method, but that class never retains it! It would be much cleaner if you'd follow Apple's memory management guidelines: your classes should only release objects that they own (i.e., that they themselves retained earlier). For example, you can do this by declaring the array's property retain:
#property (retain) NSMutableArray *colourPalettesContainer;
(To prevent leaking the array, you'll also need to release or autorelease it in the newPalette method. Retain and release should always come in close pairs.)
But even better, why not simply create the array in the app delegate's init method, or in its accessor (if for some reason you want to continue creating it only on its first use)? Unless you want to replace all palettes at once, there is no reason to let the array be assigned to from outside the app delegate.
#interface PalettesAppDelegate : NSObject <UIApplicationDelegate> {
#private
NSMutableArray *colourPalettesContainer;
}
#property (readonly) NSMutableArray *colourPalettesContainer;
#end
#implementation PalettesAppDelegate
- (NSMutableArray *)colourPalettesContainer {
if (colourPalettesContainer == nil) {
colourPalettesContainer = [[NSMutableArray alloc] init];
return colourPalettesContainer;
}
- (void)dealloc {
[colourPalettesContainer release];
[super dealloc];
}
#end
To make the design even cleaner, change the type of the colourPalettesContainer property to NSArray * and add an -addPalette: method to the app delegate. (It is rarely a good idea to publicly expose a mutable array inside a class.) You can then simply get rid of -newPalette in HandlingPalettes. (If you want to have all your palette-handling methods in HandlingPalettes, then simply move the array there. If you need to access the palettes from random places in your app, then you can simply put a retained reference to your HandlingPalettes object in the app delegate.)
Once you clean up the object ownership mess, the count mismatch will either resolve itself "by magic" or the cause will likely become much more obvious. In the latter case, check that the HomeView's dataCenter is actually the same object as the one in HandlingPalettes. (You omitted how HomeView gets its reference — are you sure you aren't creating another instance of the app delegate by accident?)
(By the way, you probably meant to use -addObjects:, not -addObject: in newPalette. Note also that all class names should be capitalized, with no exceptions: i.e., always use PalettesAppDelegate, never palettesAppDelegate. If for some reason Xcode's project template created it like that, simply rename the class. Lowercase class names are much too easy to confuse with variable names. Also, try to find better names in general: e.g., instead of HandlingPalettes, I'd use PalettesViewController (to reflect the fact that it is a subclass of UIViewController); and instead of dataCenter, I'd rather just choose appDelegate.)
I would be inclined to get rid of the newPalette method, and instead create a getter method for colourPalettesContainer in your app delegate.
ie:
appdelegate.h
#interface PalettesAppDelegate : NSObject <UIApplicationDelegate> {
NSMutableArray *colourPalettesContainer;
}
#property (non-atomic, retain) NSMutableArray *colourPalettesContainer;
#end
#implementation palettesAppDelegate
appdelegate.m
#import "appdelegate.h"
#synthesize colourPalettesContainer;
- (NSMutableArray *) colourPalettesContainer{
if(colourPalettesContainer==nil){
colourPalettesContainer=[[NSMutableArray alloc] init];
}
return colourPalettesContainer;
}
- (void)dealloc {
[colourPalettesContainer release];
[super dealloc];
}
#end
you should then be able to add items by calling
[appDelegate.colourPalettesContainer addObject:object];
I know im missing something but my friend and I can figure out what.
Firstly.. I have two .hs and .ms that I'd like to share data between - two view controllers
In the first .h i have this - that makes the variables and properties them
//top half of .h
//Passing to Submit Page
NSMutableString *messageString;
NSInteger theirTime;
}
#property (nonatomic, readwrite) NSInteger theirTime;
#property (nonatomic, retain, readwrite) NSMutableString *messageString;
/actions
#end
Then in the respective .m - sythesize them
#synthesize messageString, theirTime;
then from the new .h and .h i need to acces them.. so In view did load i do this
- (void)viewDidLoad {
messageString = [[NSMutableString alloc] init];
MemoryViewController *controller = [[MemoryViewController alloc] init];
timeInSeconds = controller.theirTime;
NSLog(#"Time = %d", timeInSeconds);
messageString = controller.messageString;
NSLog(#"Message - %#", messageString);
[controller release];
NSUserDefaults *HighScore = [NSUserDefaults standardUserDefaults];
bestTime.text= [NSString stringWithFormat:#"Best Time:%d", [HighScore integerForKey:#"integerKey"]];
currentTime.text = [NSString stringWithFormat:#"Current Time:%d", timeInSeconds];
[super viewDidLoad];
}
and at the top
#import "MemoryViewController.h"
and now the .h to show you all what the variables are
IBOutlet UILabel *bestTime;
IBOutlet UILabel *currentTime;
int timeInSeconds;
NSMutableString *messageString;
So. In short - I made variables made properties, and synthesized them, then in the view i make an instance of the other VC, then try use them to do things
Log out put
2010-04-15 20:53:09.105 Memory[3538:207] Time = 0
2010-04-15 20:53:09.107 Memory[3538:207] Message - (null)
Any ideas guys would be great... if you need more code/ less code just say.. ive tried other blogs but they all do it with app delegates.. and i dont like global variables.
Cheers
Sam
You initialised a new MemoryViewController instance in your -viewDidLoad, so of course all of its instance variables are 0 or nil. If you already have a MemoryViewController that you need to get the properties from, you need to reference that instance instead of creating a new one.