So, for my program i am using 5 different views that all need to access and share the same data. when i first started developing for iPhone, i found a way to create and store the data in the appDelegate. now, i have a large amount of variables that i access from there.
my question now, is how do memory management of them?
appDelegate.h
#property (nonatomic, retain) NSString *analysisModeForSave;
#property (nonatomic, retain) NSString *pdfPath;
#property (nonatomic, retain) NSString *state;
#property (nonatomic, retain) NSNumber *userLevel;
#property (nonatomic, retain) NSNumber *currentHiliteID;
then #synthesize them in the .m file
and use
Agri_ImaGIS_iPhoneAppDelegate *dataCenter = (Agri_ImaGIS_iPhoneAppDelegate *) [[UIApplication sharedApplication] delegate];
to access them all in the function. right now if i don't need the variable anymore, i just set it to nil. should i release them in the appDelegate's dealloc? does the memory ever get cleared other then app termination?
Although it is true that the singleton instance of Agri_ImaGIS_iPhoneAppDelegate will not be deallocated until the app finishes it is good practice to release retain properties in the dealloc method of any class. The system would clean up after you anyway in this case but would frown at you for being messy and badly behaved...
The general rule sounds:
Whenever you alloc an object, you dealloc it in the same class.
These NSNumbers and NSStrings are no different.
You can set them to nil whereever you like but you still have to release them in the dealloc.
Related
I'm confused about something. If in your .h file you have:
#property (nonatomic, strong, readonly) NSArray *categories;
and then in the .m you have:
#interface MyClass ()
#property (nonatomic, strong, readwrite) NSMutableArray *categories;
#end
If I want to later set categories in the .m file, I can do:
[self setCategories:[NSArray arrayWithArray:categories]];
But then Xcode complains that incompatible pointer types sending NSArray to NSMutableArray. I'm basically trying to hide the implementation details and have the .m use a NSMutableArray and to a consumer
use an NSArray.
[self setCategories:[NSMutableArray arrayWithArray:categories]]; // this gives no Xcode warning
By using the [NSMutableAray arrayWithArray:] method, does it still prevent the consumer of my Class from mutating my categories array?
You've done all you can in objc.
Your internal readwrite declaration needs a mutable array, so Xcode's complaining is right, you have to use a mutable for the setter.
The consumer can do everything with that object, even if it's declared as NSArray you can find out it's a NSMutableArray in reality and change it.
You can't prevent that. But your public declaration shows it should be assumed immutable. There's nothing more you can do.
I have experience with Java and Android development, and am now attempting to learn Objective-C and iPhone/iPad development. In order to help teach myself, I am re-writing an application I made for android over to iPhone.
I am now attempting to use the UISearchBar in a tableview that I have populated with names from "member" objects. However, I am having trouble using NSPredicate to retrieve the name properties from inside the member objects that I have created, as it crashes. I was able to create a workaround by making an entirely seperate array filled with just the names and use that with NSPredicate, but this is far from ideal and creates problems down the road.
So basically by doing this I was able to pinpoint the problem to either how I use NSPedicate or maybe how I set my member objects in a previous class. Just to clarify, my object is properly filled when I do go into the method that uses NSPredicate so I know my objects are not just nil.
Here is my .h for my member class.
#interface AKPsiMember : NSObject
#define CURRENT_STATUS #"Current"
#define ALUMNI_STATUS #"Alumni"
#property (nonatomic, strong) NSString *firstName;
#property (nonatomic, strong) NSString *lastName;
#property (nonatomic, strong) NSString *emailAddress;
#property (nonatomic, strong) NSString *pledgeClass;
#property (nonatomic, strong) NSString *major;
#property (nonatomic, strong) NSString *phoneNum;
And also my TableViewController .m that contains the UISearchBar method delegates
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSPredicate *resultPredicate = [NSPredicate
predicateWithFormat:#"SELF.firstName contains[c] %#",
searchText];
self.searchedMemberNameResults = [self.listedMembers filteredArrayUsingPredicate:resultPredicate];
}
And finally the error from my stack trace
'NSInvalidArgumentException', reason: '-[AKPsiMember isEqualToString:]: unrecognized selector sent to instance 0x716bbd0'
Well I feel silly. My problem was actually setting my cell.textLabel.text = to the member object instead of the string in the object. Apparently I made this change by accident some time ago when first implementing the UISearchBar and just never noticed.
My predicate is actually working correctly now! Thanks for everyone that took the time to help me out.
I have a static instance variable that is being used throughout my application. It has properties. These properties are used through my application and seem to work pretty well. However, sometimes the properties are released prematurely. What is odd is that the object that is pulling these properties keeps some and releases others. What would be a good way to insure that the properties of my object are not released prematurely.
Edit: It turns out that the issue was not premature releasing at all. It was a conversion issue. Thanks all for help.
#interface Game : NSObject
#property (nonatomic, strong) PFObject *gameObject;
//#property (nonatomic, strong) Concept *concept; // Will need to add Concept Object to GameObject once it's wrapper is done
#property (nonatomic, strong) User *initialPlayer;
#property (nonatomic, strong) User *invitedPlayer;
#property (nonatomic, strong) User *lastPlayedPlayer;
#property (nonatomic, strong) NSDate *lastPlayedDate;
#property (nonatomic, strong) NSDate *timeOutDate;
#property (nonatomic, assign) int timerTicks;
#property (nonatomic, assign) int currentRoundNumber;
#property (nonatomic, strong) User *winnerPlayer;
#property (nonatomic, assign) int initialPlayerPoints;
#property (nonatomic, assign) int invitedPlayerPoints;
#property (nonatomic, assign) int currentPlayerPoints;
#property (nonatomic, assign) GameStatus status;
#property (nonatomic, assign) int initialPlayerTimeouts;
#property (nonatomic, assign) int invitedPlayerTimeouts;
#property (nonatomic, assign) BOOL isInitialPlayer;
#property (nonatomic, strong) NSMutableDictionary *rounds;
#property (nonatomic, strong, readonly) Round *currentRound;
+(void)getActiveUserGameObjects:(PFUser *)user target:(id)target selector:(SEL)selector;
+(void)getYourTurnGameObjects:(PFUser *)user target:(id)target selector:(SEL)selector;
+(void)getTheirTurnGameObjects:(PFUser *)user target:(id)target selector:(SEL)selector;
+(void)getGameObjects:(PFUser *)user yourTurn:(id)yourTurn target:(id)target selector:(SEL)selector;
+(Game*)currentGame;
+(void)setCurrentGame:(Game*)currentGame;
..
//.m #implementation
..
static Game *sharedInstance = nil;
..
+(Game*)currentGame
{
return sharedInstance;
}
+(void)setCurrentGame:(Game*)currentGame
{
sharedInstance = currentGame;
}
...
#pragma mark - Player Setters and Getters
-(void)setInvitedPlayer:(User *)invitedPlayer
{
if (nil != invitedPlayer.userObject)
{
[self.gameObject setObject:invitedPlayer.userObject forKey:GAME_INVITED_PLAYER];
}
}
-(User*)invitedPlayer
{
NSObject *value = [self.gameObject objectForKey:GAME_INVITED_PLAYER];
if ([value isKindOfClass:[PFUser class]])
{
return [User userFromPFUser:(PFUser*)value];
}
return nil;
}
What would be a good way to insure that the properties of my object are not released prematurely.
Holding onto them by maintaining a strong reference. It is extremely unlikely that ARC is randomly releasing your data. Much more likely is that you are letting go of it when you don't mean to.
The first place I'd look is at your use of setCurrentGame:, making sure that you're not accidentally working on different Game objects at the same time in different parts of the program. First, make sure t
Your +get... methods are awkwardly named (a get prefix means a very specific thing in ObjC, and it's not what you're doing here). Havings class methods that take targets and actions like this seems a likely place to have trouble. It makes me wonder what's going on inside there.
Your conversion between two kinds of User objects is a little suspicious, and I'd make sure you're not accidentally dropping User or PFUser objects when you don't mean to.
Generally speaking, though, this question is over-vague. Are you winding up with dangling strong pointers? Are your strong pointers seeming to become nil? Is your game object itself becoming nil? How do you know when things are being "released?" Or do you mean that they're deallocating? Have you put a breakpoint in dealloc to see who had the last reference to the object?
Make sure your properties are (retain) type (same as strong, I think), and keep an instance refereed to in the app delegate (so that ARC sees the reference as valid for the entire execution of your program).
[[self numSidesBox] setName: #"numSidesBox"];
This line of code receives the SIGABRT signal and i don't know why. numSidesBox is an instance of my subclass of UITextField. I have an NSString ivar that uses the
#property (nonatomic, retain) NSString *name;
way of creating setters/getters. I have no idea what's causing this problem.
Why not try:
self.numSidesBox.name=#"numSidesbox"
This assumes you have the following in your numSidesBox header:
#property (nonatomic, retain) NSString*name;
and in your .m:
#synthesize name;
This is just a general idea to get you started and point you in the right direction; you might prefer something other than retain and will also need your numSidesBox object similarly synthesized in the current .h/.m to use dot notation on it.
Additionally, just because numSidesBox has an ivar, does not mean it actually exists in memory. Before you can use it, you have to at some point initialize it with alloc and init or a custom or dedicated initializer.
Note: the below is using iOS with Automatic Reference Counting (ARC) enabled. I think ARC may have a lot to do with why it isn't working as this is set up as per examples i've found via google.
I am trying to create a protocol to notify a delegate of the filename the user selects from a UITableView.
FileListViewController.h
#protocol FileListDelegate <NSObject>
- (void)didSelectFileName:(NSString *)fileName;
#end
#interface FileListViewController : UITableViewController
{
#private
NSArray *fileList;
id <FileListDelegate> delegate;
}
#property (nonatomic, retain) NSArray *fileList;
#property (nonatomic, assign) id <FileListDelegate> delegate;
#end
FileListViewController.m
#import "FileListViewController.h"
#implementation FileListViewController
#synthesize fileList;
#synthesize delegate;
This gives an error at the
#synthesize delegate;
line which is "FileListViewController.m: error: Automatic Reference Counting Issue: Existing ivar 'delegate' for unsafe_unretained property 'delegate' must be __unsafe_unretained"
If i change FileListViewController.h putting __weak and (weak) then it will run.
#protocol FileListDelegate <NSObject>
- (void)didSelectFileName:(NSString *)fileName;
#end
#interface FileListViewController : UITableViewController
{
#private
NSArray *fileList;
__weak id <FileListDelegate> delegate;
}
#property (nonatomic, retain) NSArray *fileList;
#property (weak) id <FileListDelegate> delegate;
#end
But when I try to set the delegate the app crashes. A view called 'ImportViewController' is creating a view from 'FileListViewController' and setting the delegate to itself (ImportViewController) so I can implement my custom protocol of 'didSelectFileName'. The error I get is;
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ImportViewController setDelegate:]: unrecognized selector sent to instance 0x6c7d430'
The code I am running is;
ImportViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
FileListViewController *fileListViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"filelist"];
[fileListViewController setDelegate:self];
[self.navigationController pushViewController:fileListViewController animated:YES];
}
My Questions are:
Why does putting (weak) and __weak in make it work? I don't
understand why this works as I found it googling and there wasn't an
explanation.
Why can't I set my delegate using this
'[fileListViewController setDelegate:self];' ? It seems like the
compiler doesn't know 'delegate' exists.
Under ARC ivars default to strong. So the error
Automatic Reference Counting Issue: Existing ivar 'delegate' for unsafe_unretained property 'delegate' must be __unsafe_unretained"
is telling you that you've declared a property with __unsafe_unretained (assign) ownership, where the underlying ivar has __strong ownership, which is illegal. To avoid the error, you have 3 options:
Omit the ivar. It's not necessary to declare an ivar for a synthesized property. The ivar will be declared implicitly with ownership matching your property.
Define the ivar to match your (assign) property declaration: __unsafe_unretained id <FileListDelegate> delegate;
Define the property to match the ivar's implicit __strong ownership: #property (weak) id <FileListDelegate> delegate;
Personally, I'd omit the ivar declaration so you have the ownership semantics in one place, on the property declaration.
It seems that with :
FileListViewController *fileListViewController =
[self.storyboard instantiateViewControllerWithIdentifier:#"filelist"];
you didn't get an FileListViewController object. Look at the message it says :
-[ImportViewController setDelegate:]: unrecognized selector sent to instance 0x6c7d430
and that why your app crashes. Also try to define a retain property, instead of just assign, in case the delegate is deallocated elsewhere, your app won't crash.
I just ran across this same issue, forcing me to finally delve into the ARC documentation.
Also try to define a retain property, instead of just assign, in case the delegate is deallocated elsewhere, your app won't crash.
To maybe clarify the above quote from user756245 's answer, based on my reading I don't think that iOS 5 has changed the best practice that you shouldn't be retaining your delegate as this is a good way to leak. I think the __weak and (weak) tokens are annotations for the compiler for the sake of being able to correctly deal with generating code for the delegate.