Objective C Reassignment/Memory Management Crash - objective-c

As a relative Objective-C beginner, I'm obviously still not grasping certain memory management rules. I can't figure out how to make this not crash:
#interface MyClass { NSArray *playerArray4th; }
- (void) viewDidLoad { playerArray4th = [self getAudioPlayersForSoundFile:#"rimshot" ofType:#"aif"]; }
- (NSArray*) getAudioPlayersForSoundFile:(NSString*)soundFileName ofType:(NSString*)soundFileType {
//code instantiating objects....
NSArray *toRet = [[NSArray alloc] initWithObjects:toRetTickPlayer,toRetTickPlayerCopy,toRetTickPlayerCopy2,toRetTickPlayerCopy3, nil];
return toRet;
}
Then later, in a different function:
NSArray *currentArray = playerArray4th;
[currentArray release];
currentArray = nil;
currentArray = [self getAudioPlayersForSoundFile:fileName ofType:ofType];
And it crashes when trying to access the array again:
- (void) playSound:(NSString*)soundType {
AVAudioPlayer *currentPlayer;
if ([soundType isEqualToString:#"4th"]) {
if (playerArray4thCounter >= [playerArray4th count]) playerArray4thCounter = 0;
NSLog(#"Playing from array: %#",playerArray4th);
currentPlayer = [playerArray4th objectAtIndex:playerArray4thCounter];
playerArray4thCounter++;
}
}

Try to learn about properties and about using getters and setters. Don't take shortcuts unless you know exactly what's going on.
So define the playerArray4th property in your header file:
#property (nonatomic,retain) NSArray *playerArray4th;
And then in your .m file create getter/setter:
#synthesize playerArray4th;
Then, always use self.playerArray4th for assigning and getting the variable. The prior objects will be released when needed.
So this will not leak:
self.playerArray4th = [NSArray arrayWithObjects:#"text",#"text",nil];
self.playerArray4th = [NSArray arrayWithObjects:#"new array",#"text",nil];
because the second assignment releases the first array.
Furthermore, read about using autorelease. In short, if you alloc, copy or new, you should either release or autorelease. There's a lot to read about this here on SO which I will not repeat here now.
Don't forget to put self.playerArray4th = nil; in your dealloc method.

Related

Better way than write dozens of empty getters?

I use lazy instantiation on my properties, to have my class created and used as fast as possible. To achieve this, I write lots of 'empty' getters like this:
- (VMPlacesListFilter *)currentFilter
{
if (!_currentFilter) {
_currentFilter = [[VMPlacesListFilter alloc] init];
}
return _currentFilter;
}
They are all the same: if the instance variable is nil, call the -alloc and -init on the class of the property, then return the instance variable. Very common and straightforward.
If I don't create this getter by myself, Objective-C's automatic synthesization creates a getter for me, which does only the returning part (does not init the object if the instance variable is nil).
Is there any way to avoid writing this boilerplate code?
Nope, I'm afraid there's no good way around it, if you really want to have lazy initialization. Personally, I usually save lazy initialization for stuff that could really be time consuming or memory intensive (say, loading images or view controllers), and initialize cheap stuff (like simple data structures or model objects) in init.
- (instancetype) init {
self = [super init];
if( self ) {
_cheapThing1 = [NSMutableArray array];
_cheapThing2 = [[MyModelObject alloc] init];
}
return self;
}
- (ExpensiveThing*) expensiveThing
{
if( _expensiveThing == nil ) {
_expensiveThing = [[ExpensiveThing alloc] init];
}
return _expensiveThing;
}
Unless you're loading something from disk or the network, I wouldn't worry too much about initialization time. Of course, profile it.
I know this is an Objective-C question, but it's worth noting that Swift has lazy initialization built-in.
lazy var currentFilter = VMPlacesListFilter()
First off, I totally agree with #zpasternack that "lazy load" should not be misused. However, automatically generating setters and getters is completely doable with the power of Objective-C runtime. In fact, CoreData is doing this.
Anyway, I have come up with some stupid code implementing a class called LazyClass, in which you can declare dynamic properties like lazyArray (see below). Using dynamic method resolution, when the property is accessed for the first time, a getter that calls the corresponding class's default +alloc and -init method will be automatically added to the class. All underlying instance variables are stored in an NSMutableDictionary called myVars. Of course you can manipulate ivars through the runtime API as well, but using a dictionary should save some work.
Please note that this implementation just shows the basic idea of how it works. It lacks error checking and is not supposed to be shipped.
LazyClass.h
#interface LazyClass : NSObject
#property NSMutableDictionary *myVars;
// lazily initialized property
#property NSArray *lazyArray;
#end
LazyClass.m
#import "LazyClass.h"
#import <objc/objc-runtime.h>
#implementation LazyClass
#dynamic lazyArray;
- (instancetype)init {
self = [super init];
self.myVars = [NSMutableDictionary dictionary];
return self;
}
- (NSMutableDictionary *)getMyVars {
return self.myVars;
}
// the generated getter method
id dynamicGetterMethodIMP(id self, SEL _cmd) {
// selector name, which is also the property name
const char *selName = sel_getName(_cmd);
NSString *selNSName = [NSString stringWithCString:selName encoding:NSUTF8StringEncoding];
NSString *keyPath = [NSString stringWithFormat:#"myVars.%#", selNSName];
if (![self valueForKeyPath:keyPath]) {
// get the actual type of the property
objc_property_t property = class_getProperty([self class], selName);
const char *attr = property_getAttributes(property);
NSString *attrString = [[NSString alloc] initWithCString:attr encoding:NSUTF8StringEncoding];
NSString *typeAttr = [[attrString componentsSeparatedByString:#","] firstObject];
NSString *typeName = [typeAttr substringWithRange:NSMakeRange(3, typeAttr.length - 4)];
// the default initialization
Class typeClass = NSClassFromString(typeName);
[self setValue:[[typeClass alloc] init] forKeyPath:keyPath];
}
return [self valueForKeyPath:keyPath];
}
// the generated setter method
void dynamicSetterMethodIMP(id self, SEL _cmd, id value) {
// get the property name out of selector name
// e.g. setLazyArray: -> lazyArray
NSString *propertyName = NSStringFromSelector(_cmd);
propertyName = [propertyName stringByReplacingOccurrencesOfString:#"set" withString:#""];
propertyName = [propertyName stringByReplacingOccurrencesOfString:#":" withString:#""];
propertyName = [NSString stringWithFormat:#"%#%#", [propertyName substringToIndex:1].lowercaseString, [propertyName substringFromIndex:1]];
NSString *keyPath = [NSString stringWithFormat:#"myVars.%#", propertyName];
[self setValue:value forKeyPath:keyPath];
}
// dynamic method resolution
+ (BOOL)resolveInstanceMethod:(SEL)aSEL {
if ([NSStringFromSelector(aSEL) containsString:#"set"]) {
class_addMethod([self class], aSEL, (IMP)dynamicSetterMethodIMP, "^?");
} else {
class_addMethod([self class], aSEL, (IMP)dynamicGetterMethodIMP, "v#:");
}
return YES;
}
#end
Documentation
If it's the verboseness that bothers you, I suppose you could compress lazy initialisers that only need one-line initialization using the ternary operator:
- (VMPlacesListFilter *)currentFilter
{
return _currentFilter ? : (_currentFilter = [[VMPlacesListFilter alloc] init]);
}
DISCLAIMER: I don't do this, but it's interesting that it can be done

Remove pointer to object from NSMutableArray while keeping object?

I am trying to remove a pointer in an NSMutableArray that points to an object in another array without deleting the object itself. E.g.:
// In ViewController.m – Code abridged and somewhat simplified
#interface ViewController ()
#property (nonatomic, strong) NSMutableArray *objectPool;
#property (nonatomic, strong) NSMutableArray *objectsOwnedByFriend;
#property (nonatomic, strong) NSMutableArray *objectsOwnedByMe;
- (void)transferPointerToObjectFromFriendToMe;
- (void)copyPointerToObjectFromFriendToMe;
#end
#implementation ViewController
#synthesize objectPool = _objectPool;
#synthesize objectsOwnedByFriend = _objectsOwnedByFriend;
#synthesize objectsOwnedByMe = _objectsOwnedByMe;
- (void)setObjectPool:(NSMutableArray *)objectPool
{
_objectPool = objectPool;
}
- (NSMutableArray *)objectPool
{
if (!_objectPool) _objectPool = [[NSMutableArray alloc] initWithArray:self.objects]; // self.objects is a mutable array containing multiple NSObjects
return _objectPool;
}
- (void)setObjectsOwnedByFriend:(NSMutableArray *)objectsOwnedByFriend
{
_objectsOwnedByFriend = objectsOwnedByFriend;
}
- (NSMutableArray *)objectsOwnedByFriend
{
if (!_objectsOwnedByFriend)
{
_objectsOwnedByFriend = [[NSMutableArray alloc] init];
[_objectsOwnedByFriend addObjectsFromArray:self.objectPool];
}
return _objectsOwnedByFriend;
}
- (void)setObjectsOwnedByMe:(NSMutableArray *)objectsOwnedByMe
{
_objectsOwnedByMe = objectsOwnedByMe;
}
- (NSMutableArray *)objectsOwnedByMe
{
if (!_objectsOwnedByMe) _objectsOwnedByMe = [[NSMutableArray alloc] init];
return _objectsOwnedByMe;
}
- (void)transferPointerToObjectFromFriendToMe
{
[self.objectsOwnedByMe addObject:[self.objectsOwnedByFriend lastObject]];
[self.objectsOwnedByFriend removeLastObject];
}
- (void)copyPointerToObjectFromFriendToMe
{
[self.objectsOwnedByMe addObject:[self.objectsOwnedByFriend lastObject]];
}
#end
In the above code, when I use transferPointerToObjectFromFriendToMe, removing the last object removes both the pointer to it in self.objectsOwnedByFriend (as I want) and also the object itself in self.objectPool (which I don't want to happen).
What I would like is an array (self.objectPool) that contains all of the actual objects and then two mutable arrays (self.objectsOwnedByFriend and self.objectsOwnedByMe) that contains pointers to objects in self.objectPool and the ability to add and remove more pointers referencing objects in self.objectPool to self.objectsOwnedByFriend and self.objectsOwnedByMe.
Also, when I use either transferPointerToObjectFromFriendToMe or copyPointerToObjectFromFriendToMe, the object doesn't seem to be added properly, as a subsequent check via self.objectsOwnedByMe.count results in 0 instead of 1.SOLUTION = My lazy instantiation for self.objectsOwnedByMe was missing in my original code :SI was able to check whether self.objectsOwnedByMe was properly created via:
NSLog(#"self.objectsOwnedByMe = %#", self.objectsOwnedByMe);
** My first StackOverflow question! ** I hope I was clear...couldn't find a a similar question so apologies if I missed an old thread. Let me know if you need more info to diagnose. (I am trying to learn Obj-C.)
Typo :P Sorry peeps. In my actual code in Xcode I had:
- (void)setObjectPool:(NSMutableArray *)objectPool
{
_objectPool = objectPool;
}
- (NSMutableArray *)objectPool
{
if (!_objectPool) _objectPool = [[NSMutableArray alloc] initWithArray:self.objects];
return _objectsOwnedByFriend;
}
I think my mistake is super obvious (and if not, the mistake was that my getter for objectPool was returning _objectsOwnedByFriend...copy/paste error that I somehow missed).
Everything works now!
This is very peculiar and confusing code. I suspect the problem is that something is calling one of the setters, -setObjectPool: or -setObjectsOwnedByFriend:, with the array of the other object. Those setters simply make the ivar refer to the object that was passed in. Because of that, they are very prone to lead to objects being shared.
Typically, a property like that would be declared and implemented with copy semantics.
It looks like self.objectsOwnedByMe is never initialized and you are therefore always working with nil instead of an actual NSMutableArray.
Somewhere (perhaps in a custom getter for objectsOwnedByMe as below?) you need to create an array before you start using it:
- (NSMutableArray *)objectsOwnedByMe {
if (_objectsOwnedByMe == nil) {
_objectsOwnedByMe = [[NSMutableArray alloc] init];
}
return _objectsOwnedByMe;
}
This would explain both problems: Since it is nil it never retains the objects and therefore they go away when removed from the other array, and also why they are never added to the _objectsOwnedByMe array.

NSMutableDictionary Singleton issue

I am coding Objective-C using the Cocos2D framework, and I have a singleton used for multiple purposes. One new purposes is to get and set character's "states" which are strings. I've recently made an NSDictionary for this purpose, but I have issues with the program freezing up when a method inside the singleton is called.
Here's the singleton code. I'm just leaving in the character state stuff:
.h
#interface ExGlobal : NSObject {
NSArray *charStates_keys;
NSArray *charStates_objects;
NSMutableDictionary *charStates;
}
#property(nonatomic, retain) NSMutableDictionary *charStates;
+(ExGlobal*)sharedSingleton;
- (NSString *)charState:(NSString *)charName;
- (void)set_charState:(NSString *)value forCharName:(NSString *)charName;
#end
.m
#import "ExGlobal.h"
#implementation ExGlobal
#synthesize charStates;
static ExGlobal* _sharedSingleton = nil;
+(ExGlobal*)sharedSingleton {
#synchronized([ExGlobal class]) {
if (!_sharedSingleton) {
[[self alloc] init];
}
return _sharedSingleton;
}
return nil;
}
+(id)alloc {
#synchronized([ExGlobal class]) {
NSAssert(_sharedSingleton == nil, #"Attempted to allocate a second instance of a singleton.");
_sharedSingleton = [super alloc];
return _sharedSingleton;
}
return nil;
}
-(id)init {
self = [super init];
if (self != nil) {
// initialize stuff here
exitName = #"ruinsSkyMid";
sceneChangeKind = #"reborn";
charStates = [[NSMutableDictionary alloc] init];
charStates_keys = [NSArray arrayWithObjects:#"Feathers", #"Hummus", nil];
charStates_objects = [NSArray arrayWithObjects:#"at wall", #"with Feathers", nil];
charStates = [NSMutableDictionary dictionaryWithObjects:charStates_objects forKeys:charStates_keys];
}
return self;
}
- (NSString *)charState:(NSString *)charName{
NSString *value = [charStates objectForKey:charName];
return value;
}
- (void)set_charState:(NSString *)charState forCharName:(NSString *)charName{
[charStates setObject:charState forKey:charName];
}
- (void)dealloc {
//I know it doesn't get called, but just in case
[charStates release];
[super dealloc];
}
#end
It's unclear to me what exactly the issue is when it freezes. When this happens, all I get in the console is:
Program received signal: “EXC_BAD_ACCESS”.
warning: Unable to read symbols for /Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.3.5 (8L1)/Symbols/Developer/usr/lib/libXcodeDebuggerSupport.dylib (file not found).
Previous frame inner to this frame (gdb could not unwind past this frame)
Previous frame inner to this frame (gdb could not unwind past this frame)
Which I'm sure doesn't help finding the issue. I found if I redefine charStates_keys, charStates_objects and charStates inside both the charState and set_charState methods, it seems to work without freezing, except set_charState does not change the state.
It isn't freezing, it is crashing. Hence the EXC_BAD_ACCESS. It looks like your Xcode installation is borked, too, as the two messages following should not happen.
Note that methods should not have _s in the name; not a cause of the problem, but a comment on following convention.
You aren't retaining charStates and that is likely the cause of the crash.
Not an answer as such but I didn't have enough space in the comments field above to post this, but it might be useful.
As bbum already said, your lack of retaining charStates is likely the problem.
If you are confused about when to retain and not retain objects there's a really good book called "Learn Objective-C on the Mac" and I know it's a Mac book but most of it applies to iPhone too. On page 171 of chapter 9 (Memory Management) it talks about the "Memory Management Rules" and how if you are confused about when to retain or not then you don't understand the simple rules of Objective C memory management.
Essentially if you create an object using new, alloc or copy, then the retain count is automatically set to 1 so the object is retained and does not require you to retain it and will require a subsequent release to deallocate.
If you create the object any other way then the object will be an autoreleased object.
Obviously these rules only apply within the standard iOS libraries and can't necessarily be applied to third party libraries.
I recommend anyone who doesn't fully understand memory management in Objective C read this book. I found highly enlightening even for my iPhone work.
Hope that helps/.

making NSArray global

i have NSarray which i want to acces from all of my methods,(i want it Global), i m going to populate this array in one of my methods defined in .m file(only once).
my question is ... is it really possible to declare a NSArray in .h and define it place somewhere else or it just has to be defined when it is declared(initialization).
MY CURRENT CODE
.h file
#interface slots2ViewController : UIViewController {
NSArray* paylinesArr;
}
i m calling follwing method from ViewDidLoad
.m file
-(void)init_payline_arr
{
NSString* filePath = #"/Users/net4uonline/Desktop/slots2/paylines.txt";//filepath...
NSString *fileContents = [NSString stringWithContentsOfFile: filePath];
paylinesArr = [fileContents componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
}
i m not able to use paylinesArr array from other methods the app crashes if follwing function is getting called
-(IBAction)ShowVal
{
NSLog(#"number of elements! %#",[paylinesArr count]);
}
Or
should i use NSMutabbleArray instead?
if you want to see then i have uploaded my desktop video while i m using debug tools!
the link to video
in this video i press the record button of the debugger(i have ns zombie enabled and the retain count as well),the app starts,i press spin button and apparently it crashes...then i show you the code which has
paylinesArr = [[fileContents componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]] retain];
which retains the paylineArr
NSMutableArray won't help you! The reason of your error is that your paylinesArr variable is autorelease variable, so probably it was deallocated before ShowVal is called. Try to retain it like
-(void)init_payline_arr {
...
paylinesArr = [[fileContents componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]] retain];
...
}
This should work. But don't forget to release it in viewDidUnload method:
- (void)viewDidUnload {
[super viewDidUnload];
...
[paylinesArr release];
}

Obj-c, how do I create function which will populate an NSDictionary and gain a value from the function?

I've been reading about NSArrays and NSDictionaires and I think I need the later. I'm trying to populate an object from a small database table. So I can access the string values via a record id. I have to do this several times so putting it into an object makes sense.
I have the basics...
- (void)viewDidLoad {
// WORKING START
NSMutableDictionary *dictCategories = [[NSMutableDictionary alloc] init];
[dictCategories setValue:#"Utility" forKey:#"3"];
[dictCategories setValue:#"Cash" forKey:#"5"];
NSString *result;
result = [dictCategories objectForKey:#"3"];
NSLog(#"Result=%#", result);
// WORKING END
// Can't get this bit right, current error Request for member
// 'getCategories' in something not a structure or union
NSMutableDictionary *dictCategories2 = self.getCategories;
NSLog(#"Result2=%#", [dictCategories2 objectForKey:#"5"]);
[super viewDidLoad];
}
-(NSMutableDictionary*)getCategories {
NSMutableDictionary *dictCategories = [[NSMutableDictionary alloc] init];
[dictCategories setValue:#"Utility" forKey:#"3"];
[dictCategories setValue:#"Cash" forKey:#"5"];
return dictCategories;
}
you are calling the method wrong,try [self getCategories]
You're not being clear on what isn't working, but a few things that are obviously wrong (JonLOo might be spot on though) ...
Firstly. You're using the wrong methods, or at least there's a better one -- setValue:forKey: should/could be setObject:forKey: instead. This might be one of the reasons for your issue.
Secondly. You're over-allocating and not releasing properly. dictCategories2 in your viewDidLoad will vanish into the void and bring with it the allocated memory for dictCategories defined in the getCategories method. An easy standard fix for this is to change
NSMutableDictionary *dictCategories = [[NSMutableDictionary alloc] init];
in getCategories into
NSMutableDictionary *dictCategories = [NSMutableDictionary dictionary];
It will be autoreleased using the latter method by the system.
Thirdly. You want to read up on #property. Instead of getFoo, setBar, the Ob-C standard is to use #properties to (pre)define setters and getter methods. You can then override these to populate default data into your methods when appropriate. You also (probably) want to store the dictionary in your interface as an instance variable, rather than letting it be deallocated all the time. Example of a #property implementation that does this:
#interface foo {
NSMutableDictionary *ingredients;
}
#property (nonatomic, retain) NSMutableDictionary *ingredients;
#end
// ....
#implementation foo
#synthesize ingredients;
// ...
// the #synthesize command above will create getter and setter methods for us but
// we can override them, which we need to do here
- (NSMutableDictionary *)ingredients
{
if (ingredients != nil) {
// we've already got an ingredients variable so we just return it
return ingredients;
}
// we need to create ingredients
ingredients = [[NSMutableDictionary alloc] init];
[ingredients setObject:#"foo" forKey:#"bar"]
return ingredients;
}
In the viewDidLoad method (or anywhere else where you think ingredients might not have been initialized yet), you would do e.g.
NSMutableDictionary *dict = self.ingredients;
Anywhere else you can opt to use just ingredients without self, but if it's nil, your method will never be called, and you will get nil thrown at you.
This is useful in many cases, and is necessary if we want to ever read or write the ingredients variable from outside of our class. It's outside of what you're asking about, but I brought it up because you're trying to do something similar with self.getCategories.
Hope that helps.