iOS 10 NSNumber crash with enumerations - enums

I am having a very weird issue relating to NSNumber objects for my enumerated values and access to them on a device running iOS os version 10.
Just as a disclaimer - this issue does not happen in other iOS os versions.
I have declared an enum like so:
typedef NS_ENUM(NSInteger, MYENUM) {
FIRST = 1500,
SECOND = 1700,
THIRD = 1900,
...
};
When using this enum, I am passing it along in this fashion:
[[MyObject alloc] initObjectWith:#(FIRST)];
Excluding the inner logic, I am using the enum in a dictionary and thus need to convert it to a NSNumber.
While doing so, the application crashes, because the enum is somehow not a NSNumber, but rather a NSIndexPath.
Why does this happen?
When I remove the boxed literal and change the method signature to accept a NSInteger, this crash disappears.
I have tried searching online for this type of issue, but have come up short.
Further Explanation (per comment)
No special logic happens inside the init method for myObject, just assigning the property which is defined as a NSNumber to the parameter that is passed.
Regarding the crash log, Xcode is infamous in providing not so useful crash logs and all I am seeing is EXC_BAD_ACCESS, which could either mean accessing an object that has been released or a potential memory leak.
The MyObject class is defined as follows:
header file:
#interface ISNEvent : NSObject
#property(nonatomic, assign) NSNumber* number;
-(instancetype)initObjectWith:(NSNumber*)number;
#end
.m file:
- (instancetype)initObjectWith:(NSNumber*)number {
self = [super init];
if (self) {
_number = number;
}
return self;
}

You have defined your property with assign memory semantics:
#property(nonatomic, assign) NSNumber* number;
That means that you’ll get a reference to whatever you supply, but you won’t keep a strong reference and you won’t nil your reference when the object is deallocated. That’s the worse of both worlds, because you’re keeping a dangling reference to an object that you’re allowing to be deallocated. As you said, this particular error “could ... mean accessing an object that has been released”, and that’s precisely what’s going on here.
You might consider temporarily turning on zombies (command+<) or “Product” » “Scheme” » “Edit Scheme...” and go to the “Diagnostics” section of the “Run” settings, and see if your behavior changes. You’ll probably no longer see that NSIndexPath (or whatever) reference, but rather some confirmation that the NSNumber instance has been deallocated.
Anyway, you undoubtedly meant to make this NSNumber property a strong reference:
#property(nonatomic, strong) NSNumber *number;
The other solution would be to make it weak, allowing it to be deallocated, but safely setting your reference to nil. That’s safer than assign, but I also doubt that’s what you intended. And the third alternative would be copy, which is what we sometimes use with mutable types, which isn’t applicable here.
Bottom line, nowadays, I’d advise against ever using assign memory semantics with any object types. Use strong, copy, or weak. In this case, strong is what you want. Only use assign with primitive data types (e.g. NSInteger, CGFloat, etc.), but not with object types.
And, remember, when you’re done testing with the zombies, turn that diagnostic feature off.

Related

Cocoa bindings and KVO, unregister the observer, when the observing object gets `dealloced`

How can i unregister the observer, when the observing object gets dealloced?
How can cocoa bindings handle a situation when the observed objects gets deallocated?
By using manual KVO, i have to remove the observing (removeObserver) before dealloc the object... how does Cocoa bindings handle this (stop observing on dealloc of the observed object)?
Update 2017
As #GregBrown has pointed out in the comments the original 2013 answer does not work in 2017. I assume the original answer did work in 2013, as my practice is not to answer without testing, but I no longer have any code I used.
So how do you do solve this in 2017? The simplest answer is swizzling, which some will find a contradiction but it need not be when using blocks. Below is a quick proof-of-concept with the following caveats:
This is not thread safe. Consider what might happen if two or more threads execute the code at the same time. Standard techniques will address that.
Efficiency was not a consideration! For example, you might wish to swizzle dealloc once per class and keep a list of observer/keypath in a per-instance associated object.
This code only supports auto-removal, you cannot manually choose to remove an observer. You might wish to change that.
The code:
#implementation AutoRemovedKVO
typedef void (*DeallocImp)(id, SEL);
+ (void)forTarget:(NSObject *)target
addObserver:(NSObject *)observer
forKeyPath:(NSString *)keyPath
options:(NSKeyValueObservingOptions)options
context:(nullable void *)context
{
// register the observer
[target addObserver:observer forKeyPath:keyPath options:options context:context];
// swizzle dealloc to remove it
Class targetClass = target.class;
SEL deallocSelector = NSSelectorFromString(#"dealloc");
DeallocImp currentDealloc = (DeallocImp)method_getImplementation( class_getInstanceMethod(targetClass, deallocSelector) );
// don't capture target strongly in block or dealloc will never get called!
__unsafe_unretained NSObject *targetPointer = target;
void (^replacementBlock)(id self) = ^(__unsafe_unretained id self)
{
if (self == targetPointer)
[targetPointer removeObserver:observer forKeyPath:keyPath];
currentDealloc(self, deallocSelector);
};
class_replaceMethod(targetClass, deallocSelector, imp_implementationWithBlock(replacementBlock), "v#:");
}
#end
Both uses of __unsafe_unretained are to work around consequences of ARC. In particular methods usually retain their self argument, dealloc methods do not, and blocks follow the same retain-as-needed model. To use a block as the implementation of dealloc this behaviour needs to be overridden, which is what __unsafe_unretained is being used for.
To use the above code you simply replace:
[b addObserver:a forKeyPath:keyPath options:options context:NULL];
with:
[AutoRemovedKVO forTarget:b addObserver:a forKeyPath:keyPath options:options context:NULL];
Allowing for the above caveats the above code will do the job in 2017 (no guarantee for future years!)
Original 2013 Answer
Here in outline is how you can handle this, and similar situations.
First look up associated objects. In brief you can attach associated objects to any other object (using objc_setAssociatedObject) and specify that the associated object should be retained as long as the object it is attached to is around (using OBJC_ASSOCIATION_RETAIN).
Using associated objects you can arrange for an observer to be automatically removed when the observed object is deallocated. Let X be the observer and Y be the observed objects.
Create an "unregister" class, say Z, which takes (via init) an X & Y and in its dealloc method does removeObserver.
To setup the observation, X:
Creates an instance of Z, passing itself and Y.
Registers itself as an observer of Y.
Associates Z with Y.
Now when Y is deallocated Z will be deallocated, which will result in Z's dealloc being called and unregistering the observation of X.
If you need to remove the observation of X while Y is still active you do this by removing the associated object - and doing so will trigger its dealloc...
You can use this pattern whenever you want to trigger something when another object is deallocated.
HTH
From the KVO guide (emphasis mine): The key-value observing addObserver:forKeyPath:options:context: method does not maintain strong references to the observing object, the observed objects, or the context. You should ensure that you maintain strong references to the observing, and observed, objects, and the context as necessary.
Cocoa Bindings manage the strong references during bind: and unbind:.
To answer your question "How can i unregister the observer, when the observing object gets dealloced?": You don't unregister the observer, because the observer should maintain a strong reference to the observed object. Thus the observed object doesn't get deallocated.
Another way to think of this, you are observing properties, but not the observed object itself. So you only care when properties are set to nil. Because you are maintaining a strong reference as an observer, the observed object will not be deallocated until the observing object is done observing it.
So if the observed object was removed as a property you are observing of another object, that would cause you to stop observing it (releasing the strong reference) and then allow the observed object to be deallocated. That property you are observing may be a collection of objects, so you would observe the object being removed, causing you to stop observing and allowing the object to dealloc.
My patter that i tried and looks to work : X wants to observe Y
1) In Y declare a property
#property (assign) id dealloced;
2) In Y's dealloc
- (void)dealloc {
self.dealloced = self;
}
3) In X observe also Y's keyPath dealloced
[Y addObserver:self forKeyPath:#"dealloced" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL];
4) In X just handle the KVO change for dealloced and unregister all observing
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
...
if ([keyPath isEqual:#"dealloced"]) {
id obj = change[#"new"];
[obj removeObserver:self forKeyPath:#"dealloced"];
// remove other observing as well
}
...
}
And in X we don't even need to hold a reference to Y

implementing custom accessor methods

I am reading "Core Data Programming Guide". It contains this text:
You must, however, change attribute values in a KVC-compliant fashion.
For example, the following typically represents a programming error:
NSMutableString *mutableString = [NSMutableString stringWithString:#"Stig"];
[newEmployee setFirstName:mutableString];
[mutableString setString:#"Laura"];
For mutable values, you should either transfer ownership of the value
to Core Data, or implement custom accessor methods to always perform a
copy. The previous example may not represent an error if the class
representing the Employee entity declared the firstName property
(copy) (or implemented a custom setFirstName: method that copied the
new value). In this case, after the invocation of setString: (in the
third code line) the value of firstName would then still be “Stig” and
not “Laura”.
Question regarding text: "In this case" is which case--the one where property is declared as "copy" or when its not?
Question regarding copy and programming practice:
From what I have read here:
NSString property: copy or retain?
I understand
that using copy will ensure that firstName is "Stig", not Laura
it is wise to do so because "in almost all cases you want to prevent mutating an object's attributes behind its back"
I would really like to know what is the above quoted text trying to tell us in the context of Core Data. We have to use "copy" anyway whether using Core Data or not. Also, I would be glad if someone could throw more light on point "2" (it is wise to...) above as in what will be the consequences of mutating an object's attributes behind its back?
your "Question regarding text: "In this case" is which case--the one where property is declared as "copy" or when its not?"
mis-matched the point that Apple document wants to explain, I believe.
As Apple document points out, if custom-accessor-method is implemented normally, the default implementation does NOT copy attribute values. If the attribute value may be mutable and implements the NSCopying protocol (as is the case with NSString, for example), you can copy the value in a custom accessor to help preserve encapsulation (for example, in the case where an instance of NSMutableString is passed as a value).
Here is a copying setter snippet
#interface Department : NSManagedObject
{
}
#property(nonatomic, copy) NSString *name;
#end
#implementation Department
#dynamic name;
- (void)setName:(NSString *)newName
{
[self willChangeValueForKey:#"name"];
// NSString implements NSCopying, so copy the attribute value
NSString *newNameCopy = [newName copy];
[self setPrimitiveName:newNameCopy];
[self didChangeValueForKey:#"name"];
} #end
The issue is when to use (and how) immutable values.
Since core data use KVO heavily when detecting changes done to objects, if you use a mutable property that is changed directly through it object and not through the property, CoreData will not detect the change to the object and your changes might not persist to the store.
If you use mutable NSManagedObject attributes, override the setter/getter method and use only them to mutate the underlying object (this mean that you are responsible to let CoreData know that a change did happen to the object, and it must be persisted to the store.
Also, if you use transformable properties for complex objects, you must trigger the change notifications yourself in order for CoreData to realise that a change has occurred, and the object should be re-transformed and saved when the context saves.
I would highly recommend that when it comes to simple objects like strings, you use immutable property values which will force you to go through the object properties and trigger the default KVO notification (copy attributes will also force the KVO notifications).

Is passing a controller in a construtor always a bad practice?

I occasionally instantiate a class from my view controller by passing in the view controller instance itself so that the objects that I create can invoke methods of the controller to update the view.
Is that always, often, or never a bad practice?
Concretely:
ViewController.h has
-(void)updateButtonValue:(NSString*)value;
MyObject.h has
-(id)initWithViewController:(ViewController*)aViewController;
I instantiate that class from my view controller with:
[[MyObject alloc] initWithViewController:self];
thus allowing that MyObject instance to update a button value in my view by a simple call like:
MyObject.m
[self.viewController updateButtonValue:#"example"];
It does not seem ideal since I am passing to MyObject much more (the view controller itself) than it should need, but it is certainly quick and functional. If there is a cleaner approach, such as relying on protocols, that is also succinct, a brief code sample would be much appreciated.
It is always bad practice to pass a class-typed pointer in, as you are tightly coupling your objects together (each object needs to know the class of the other, they might as well be a single object). This is what the delegate pattern is for. It minimises the info MyObject needs (minimally, nothing more than a pointer type id - preferably, a protocol specified by MyObject to offer it some behavioural guarantees)
So to translate your example
MyObject.h
replace...
-(id)initWithViewController:(ViewController*)aViewController;
with...
-(id) init;
(which you can dispense with if you have no further reason to override)
and...
#property (nonatomic, weak) id delegate;
Instantiation in myViewController (which does need to #include MyObject) ...
MyObject* object = [[MyObject alloc] init];
Followed by
object.delegate = self;
(Note that object gets a pointer to myViewController without needing to know anything else about it)
Now you can do this from inside object:
[self.delegate updateButtonValue:#"example"];
However ... you will want to ensure that your delegate can receive the message updateButtonValue:
To do this, you declare a protocol in MyObject.h with the signature of this method
#protocol MyObjectDelegate
- (void) updateButtonValue:(NSString*)string;
#end
And in your viewController, declare that you conform to this protocol using <> in the interface line
#interface ViewController <MyObjectDelegate>
(this is no big deal, ViewController already has to #include MyObject to alloc/init it, so needs no more info to do this)
And expand your property declaration thus:
#property (nonatomic, weak) id <MyObjectDelegate> delegate
Now you have given the compiler enough information for it to ensure that you can only pass conformant messages around. The brilliant thing here is that MyObject can confidently pass messages to MyViewController without needing to know anything about MyViewController other than that it is reached via the delegate pointer.

Best way of declaring private variables in cocoa

I would like to know what the recommendations are for declaring private instance variables in cocoa. This question is in the context of developing apps on the iPhone.
I am aware of at least three ways of declaring private variables:
Declare them in the interface of the h file with the modifier #private:
#interface MyClass : NSObject {
#private
NSObject * myPrivateVar;
}
Declare them in the implementation section of the m file:
#implementation MyClass
NSObject * myPrivateVar;
Declare a property in the interface of the m file (not even declaring the variable itself):
#interface MyClass ()
#property (nonatomic, retain) NSString* myPrivateVar;
#end
#implementation
#synthesize myPrivateVar;
So far, I have used extensively 2 but recently came to realize this might be dangerous due to the lack of garbage collection. Are there cases where it remains perfectly acceptable to use that method?
Is 3 more appropriate? Does the answer depend on the object type (e.g. mutable/immutable)?
Pointers to reference material discussing the trade offs for using/not using properties in general also appreciated.
Your three options have different semantics:
This creates an instance variable. Without garbage collection you need to retain/release objects you store into myPrivateVar.
This does not define an instance variable at all. Variables defined outside of the #interface and the scope of many method (or function) definitions are "global" - effectively class variables (which Objective-C has no special syntax for). Such a variable is shared by all instances of MyClass.
The difference between using a property (with or without the variable being explicitly declared) comes down to memory management. Defined as you have with retain means that there is no need for retain/release when you do not have garbage collection.
So don't use 2! Option 3 clearly has benefits if you don't have garbage collection, it provides some measure of abstraction over option 1, and is more costly - though you will probably not notice the difference outside of computationally intensive code which access the variable heavily.
Update 2015
Where garbage collection is used above ARC (automatic reference counting) is now more applicable (garbage collection is now deprecated). Also there is now a fourth option:
Declare them in the implementation section of the m file:
#implementation MyClass
{
NSObject * myPrivateVar;
}
Unlike option (2) this does declare an instance variable. The variable is private to the implementation, and with ARC memory management is automatic. The choice between this and (3) [which incidentally also no longer requires the #synthesize] comes down to choice and need; properties give you dot syntax, the ability to customise the setter and/or getter, and the copy attribute for automatic copy on assignment, but if you need none of these you can simply use the an instance variable.

Dealing with objects returned from cocoa convenience methods

I'm having a lot of issues with NSDate objects being prematurely deallocated. I suspect that the issues may be related to the way that I deal with the objects returned from NSDate convenience methods. I think that my showDate property declaration in the JKShow class should be "retain", but changing it to assign or copy seems to have no effect on the issue.
JKShow *show;
NSDate *date;
NSMutableArray *list = [[NSMutableArray alloc] init];
// Show 1
show = [[JKShow alloc] init];
//...
date = [gregorian dateFromComponents:dateComponents];
show.showDate = date;
[list addObject:[show autorelease]];
// Show 2
show = [[JKShow alloc] init];
//...
date = [gregorian dateFromComponents:dateComponents];
show.showDate = date;
[list addObject:[show autorelease]];
UPDATE
The issue was not in the code copied here. In my JKShow init method I was not retaining the date returned from the NSDate convenience method. Thanks for your help, everyone.
The date returned from dateFromComponents should be in the autorelease pool, so you are correct that your showDate property should be "retain". In fact it should be anyway (unless you specifically want "copy").
From the code you have shown it looks like you are giving ownership of your show object entirely to the list (as you're setting autorelease on them as you add them). Are you saying that the date objects are being deallocated before the show objects are coming out of the list (or the list is being deallocated)?
Also, are you using synthesised properties, or are you writing them by hand? If the latter, what is your setShowDate property method like?
You can also try logging the retainCount of the date object at different places (although I always find that autorelease really complicates that).
If showDate is a retain property that should be sufficient, given the code you have posted. Something else (probably in JKShow's implementation) may not be correct.
If you want to figure out what is going on, you can use Instruments to see examine the objects lifespan. You need to run it with the allocation tool set to remember retains and releases. By default it is set up that way if you run the leaks performance tool.
When you run Instruments like that it will record all object life spans, and the backtrace for every retain and release issued against them. If you look through the objects, find one of your dates, and look at all the retains and releases you should be able to determine where the spurious release is happening.
The code you showed has no premature-release problems. In fact, it will leak the array and everything in it, because it doesn't release the array.
Are you running with the garbage collector turned on?
Is list an instance variable or static variable, or is it a local variable?
I figured it out, thanks for all your help, but the problem was outside of the code I posted here. I was not retaining the NSDate I created in my init method. Unfortunatly the crash didn't occur until after I had created the two new NSDate objects, so I was totally barking up the wrong tree.

Resources