Why is my object's weak delegate property nil in my unit tests? - objective-c

I have a pretty simple setup for this unit test. I have a class that has a delegate property:
#interface MyClass : NSObject
...
#property (nonatomic, weak) id<MyDelegateProtocol> connectionDelegate;
...
#end
and I set the delegate in my test:
- (void)testMyMethod_WithDelegate {
id delegate = mockDelegateHelper(); // uses OCMock to create a mock object
[[delegate expect] someMethod];
myClassIvar.connectionDelegate = delegate;
[myClass someOtherMethod];
STAssertNoThrow([delegate verify], #"should have called someMethod on delegate.");
}
But the delegate is not actually set on line 3 of my unit test, so #someMethod is never called. When I change it to
myClassIvar.connectionDelegate = delegate;
STAssertNotNil(myClassIvar.connectionDelegate, #"delegate should not be nil");
it fails there. I'm using ARC, so my hunch was that the weak property was being deallocated. Sure enough, changing it to strong makes the STAssertNotNil pass. But I don't want to do that with a delegate, and I don't understand why that makes a difference here. From what I've read, all local references in ARC are strong, and STAssertNotNil(delegate) passes. Why is my weak delegate property nil when the same object in a local variable is not?

This is a bug in the iOS runtime. The following discussion has more detail. In a nutshell, the iOS ARC runtime can't seem to handle weak references to proxies. The OSX runtime can.
http://www.mulle-kybernetik.com/forum/viewtopic.php?f=4&t=252
As far as I understand from the discussion a bug report has been filed with Apple. If anyone has a sensible idea for a workaround...

I don't really know what's happening here, but OCMock returns an autoreleased NSProxy-descendant from the mockForProtocol: method, which I think is right. Maybe ARC has problems with NSProxies? Anyway, I've overcome this problem by declaring the variable __weak:
- (void)testMyMethod_WithDelegate {
// maybe you'll also need this modifier inside the helper
__weak id delegate = mockDelegateHelper();
...
It really doesn't need to be __strong (the default) in this case, as it's autoreleased and you're not keeping it around...

A workaround is to use Partial Mocks.
#interface TestMyDelegateProtocolDelegate : NSObject <MyDelegateProtocol>
#end
#implementation TestMyDelegateProtocolDelegate
- (void)someMethod {}
#end
#implementation SomeTest {
- (void)testMyMethod_WithDelegate {
id<MyDelegateProtocol> delegate = [[TestMyDelegateProtocolDelegate] alloc] init];
id delegateMock = [OCMockObject partialMockForObject:delegate]
[[[delegateMock expect] someMethod]
myClassIvar.connectionDelegate = delegate;
[myClass someOtherMethod];
STAssertNoThrow([delegate verify], #"should have called someMethod on delegate.");
}
#end

I am no ARC expert but my guess is that mockDelegateHelper() is returning a weak object. As a result delegate is nil before the second line of code executes. I would venture to guess that either the mockDelegateHelper() is the culprit or that OCMock is getting in the way with how it manipulates and creates objects.

Related

Setting default values for inherited property without using accessor

I always see people debating whether or not to use a property's setter in the -init method. My problem is how to create a default value in a subclass for an inherited property. Say we have a class called NSLawyer -- a framework class, that I can't change -- with an interface that looks like this:
#interface NSLawyer : NSObject {
#private
NSUInteger _numberOfClients;
}
#property (nonatomic, assign) NSUInteger numberOfClients;
#end
And an implementation that looks like this:
#implementation NSLawyer
- (instancetype)init
{
self = [super init];
if (self) {
_numberOfClients = 0;
}
return self;
}
#end
Now let's say I want to extend NSLawyer. My subclass will be called SeniorPartner. And since a senior partner should have lots of clients, when SeniorPartner gets initialized, I don't want the instance to start with 0; I want it to have 10. Here's SeniorPartner.m:
#implementation SeniorPartner
- (instancetype)init
{
self = [super init];
if (self) {
// Attempting to set the ivar directly will result in the compiler saying,
// "Instance variable _numberOfClients is private."
// _numberOfClients = 10; <- Can't do this.
// Thus, the only way to set it is with the mutator:
self.numberOfClients = 10;
// Or: [self setNumberOfClients:10];
}
return self;
}
#end
So what's a Objective-C newcomer to do? Well, I mean, there's only one thing I can do, and that's set the property. Unless there's something I'm missing. Any ideas, suggestions, tips, or tricks?
You should do exactly has you have; call the accessor. The declaring class typically avoids calling its own accessors in init to avoid accidentally calling an overridden accessor in a subclass that might rely on the consistency of data you haven't initialized yet. Your superclass on the other hand should be completely consistent by the time the subclass's init is run, so there is no problem using superclass accessors at that time.
Consider the common and general case: you want to set your transform in a UIView subclass. How would you solve that other than call setTransform:? Subclassing non-Apple code is no different.
Make it #protected. It is very rare to make an ivar or property private these days. Private ivars and/or properties are better declared in the implementation. For that matter #protected ivars/properties are rarely seen in Objective-C but perfectly fine.
Using a setter either as a method or with dot notation is just wrong (yes it works but is really bad form), if you want use setters/getters declare a property.

Weird memory issues, with ARC enabled

I am having a very, very strange error, probably related to memory management (even though I'm using ARC).
I have a my AppDelegate, Foo, and SubFoo (which is a subclass of Foo).
Foo.h
#protocol FooDelegate <NSObject>
- (void)didReceiveDownloadRequest:(NSURLRequest *)downloadRequest;
#end
#interface Foo : NSObject {
__weak id <FooDelegate> delegate;
}
- (void)performRequest;
#property (nonatomic, weak) id <FooDelegate> delegate;
#property (nonatomic, retain) NSString *fileIdentifier;
Foo.m
#implementation Foo
#synthesize delegate, fileIdentifier;
- (id)init {
if ((self = [super init])) {
self.delegate = nil; // I tried leaving this line out, same result.
NSLog(#"I am %p.", self);
}
return self;
}
- (void)performRequest {
// Bah.
}
#end
SubFoo.h
#interface SubFoo : Foo {
WebView *aWebView;
}
SubFoo.m
- (void)performRequest {
if (self.fileIdentifier) {
aWebView = [[WebView alloc] init];
[aWebView setFrameLoadDelegate:self];
[[aWebView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"theURL"]];
}
}
- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
NSLog(#"Finished loading.");
// ...
NSLog(#"Class Name: %#", NSStringFromClass([self class]));
NSLog(#"Memory Location of delegate: %p", self.delegate);
// ...
}
Sometimes, the class name on webView:didFinishLoadForFrame: returns a completely different class (instead of SubFoo, it returns random classes, like NSSet, NSArray, it even sometimes returns CFXPreferencesSearchListSource), other times it just crashes there with an EXC_BAD_ACCESS, and when it returns a random class on Class Name: it returns that [randomClassName delegate] is an unrecognized selector.
EDIT: When self gets set to another thing, it gets set RIGHT on webView:didFinishLoadForFrame:, and on performRequest it is ALWAYS SubFoo.
Any help here would be appreciated.
First, even though you are using ARC zeroing weak references in your project (#property (weak)), other projects and frameworks may not be (and are probably not) using zeroing weak references.
In other words, assume that all delegates in frameworks are __unsafe_unretained unless:
The delegate property is declared weak in a header
The documentation/header explicitly states otherwise
That said, let's talk about your example. Your object ownership chart looks something like this:
(Note: I'm not entirely sure which class in your project uses SubFoo. Based on common practice, I'm assuming that you have a class with a strong reference to SubFoo, and that class is also set up to be a SubFooDelegate)
Ultimately, your instance of SubFoo is losing its last strong reference and is deallocating. In a perfect ARC-enabled world, the WebView's pointer to SubFoo would nil out at this time. However, it's not a perfect world yet, and WebView's frameLoadDelegate is __unsafe_unretained. Due to run loop interaction, the WebView is outliving SubFoo. The web request completes, and a dead pointer is dereferenced.
To fix this, you need to call [aWebView setFrameLoadDelegate:nil]; in SubFoo's dealloc method. You also need to call it when you reassign aWebView, as you are losing track of the old aWebView:
SubFoo.m
#implementation SubFoo
- (void)dealloc {
[aWebView setFrameLoadDelegate:nil];
// Also nil out any other unsafe-unretained references
}
- (void)performRequest {
if (self.fileIdentifier) {
[aWebView setFrameLoadDelegate:nil]; // Protects us if performRequest is called twice. Is a no-op if aWebView is nil
aWebView = [[WebView alloc] init];
[aWebView setFrameLoadDelegate:self];
[[aWebView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"theURL"]];
}
}
- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
// ...
}
Forget the self.delegate error for now, it is a red herring if [self class] is producing the wrong result! Your results suggest you are somehow clobbering self.
Breakpoint on webView:didFinishLoadForFrame: check the self value and step through.
Comment Followup
For self to be wrong on the first statement of an instance method is, let's say, unusual (but not impossible).
It is important when an object is set as another's delegate that you make sure the delegate object's lifetime is at least as long as the one it is acting as a delegate to. Introducing ARC can make previously working code fail as it may release the delegate earlier than the code did under MRC. When this happens the call to the delegate usually fails.
However your error does not fail on the call to the delegate; the call starts - you end up in webView:didFinishLoadForFrame: - and then you find self is invalid. To actually invoke an instance method usually requires a valid value for self as it is used to determine the method implementation to call. Hence it is usual for self to be valid at the start of a method!
But note the "usually"...
So despite you having successfully reach your method, your error might be down to not having a strong reference to your SubFoo instance, you pass it as a delegate to aWebView, and by the time webView:didFinishLoadForFrame: is called your SubFoo has gone.
Make sure you're keeping a strong ref to your SubFoo instance. If you just want to test (this is not a recommended general solution!) if this is your problem you can just assign it to a local static (static SubFoo *holdMe say declared inside performRequest) in performRequest, which will keep a strong reference around at least until the next call to performRequest. If this does prove to be the problem you then need to come up with a good way to maintain the reference that fits your design.
Here's the real problem: You're creating a SubFoo object within the context of a method. So after the method completes, SubFoo is being released (before its WebView has time to load).
To fix this, you'll need to assign the SubFoo object you're creating to something persistent, like a instance variable of the class you're creating it from. That way the object will persist beyond the scope of the method it was created in and all will work as expected.
As CRD mentioned, I would say an incorrect object/bad access returned is a sign of an object being released. Sometimes it's replaced by another object, sometimes it's not so you get the bad access exception. Regarding how this could happen to self, I would imagine that this is a concurrency weird case (object is being freed on another thread).
The best way to confirm this is to run your code in Instrument's NSZombie template, it'll show you as soon as you access a freed object. It also shows when it's been retained/released so you don't have to guess.
Regarding your above comment.
SubFoo *theClass = [[SubFoo alloc] init];
You must store theClass in a
#property (strong) SubFoo *mySubFoo;
If you declare it as such:
{
SubFoo *theClass = [[SubFoo alloc] init];
}
It gets released at the closing bracket. This part of the point of ARC when that variable moves out of scope, it gets released. If you want to let it float in the ether you could use
{
__weak SubFoo *theClass = [[SubFoo alloc] init];
}
and it won't get released, but this will lead to a memory leak unless you carefully manage all the weak references. In the case of it not being released at -performRequest I'm assuming the request looks like this:
{
SubFoo *theClass = [[SubFoo alloc] init];
[theClass performRequest];
}
wheras -webView:didFinishLoadForFrame: is called at some indiscriminate time in the future.

Why rename synthesized properties in iOS with leading underscores? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How does an underscore in front of a variable in a cocoa objective-c class work?
When creating a new project in Xcode 4, the boilerplate code adds an underscore character when it synthesizes the ivars in the implementation file as:
#synthesize window = _window;
or:
#synthesize managedObjectContext = __managedObjectContext;
Can someone tell me what is being accomplished here? I'm not a complete nube, but this is one aspect of objective-C I don't understand.
Another point of confusion; in the app delegate implementation, after synthesizing the window iVar as above, in the application didFinishLaunchingWithOptions: method the window and viewController ivars are referred to using self:
self.window.rootViewController = self.viewController
[self.window makeKeyAndVisible];
but in the dealloc method it's _window, or _viewController
Thanks
This is an artifact of a previous version of the Objective-C runtime.
Originally, #synthesize was used to create accessors methods, but the runtime still required that instance variables had to be instantiated explicitly:
#interface Foo : Bar {
Baz *_qux;
}
#property (retain) Baz *qux;
#end
#implementation Foo
#synthesize qux = _qux;
- (void)dealloc {
[_qux release];
[super dealloc];
}
#end
People would prefix their instance variables to differentiate them from their properties (even though Apple doesn't want you to use underscores, but that's a different matter). You synthesize the property to point at the instance variable. But the point is, _qux is an instance variable and self.qux (or [self qux]) is the message qux sent to object self.
We use the instance variable directly in -dealloc; using the accessor method instead would look like this (though I don't recommend it, for reasons I'll explain shortly):
- (void)dealloc {
self.qux = nil; // [self setQux:nil];
[super dealloc];
}
This has the effect of releasing qux, as well as zeroing out the reference. But this can have unfortunate side-effects:
You may end up firing some unexpected notifications. Other objects may be observing changes to qux, which are recorded when an accessor method is used to change it.
(Not everyone agrees on this point:) Zeroing out the pointer as the accessor does may hide logic errors in your program. If you are ever accessing an instance variable of an object after the object has been deallocated, you are doing something seriously wrong. Because of Objective-C's nil-messaging semantics, however, you'll never know, having used the accessor to set to nil. Had you released the instance variable directly and not zeroed-out the reference, accessing the deallocated object would have caused a loud EXC_BAD_ACCESS.
Later versions of the runtime added the ability to synthesize instance variables in addition to the accessor methods. With these versions of the runtime, the code above can be written omitting the instance variables:
#interface Foo : Bar
#property (retain) Baz *qux;
#end
#implementation Foo
#synthesize qux = _qux;
- (void)dealloc {
[_qux release];
[super dealloc];
}
#end
This actually synthesizes an instance variable on Foo called _qux, which is accessed by getter and setter messages -qux and -setQux:.
I recommend against this: it's a little messy, but there's one good reason to use the underscore; namely, to protect against accidentally direct ivar access. If you think you can trust yourself to remember whether you're using a raw instance variable or an accessor method, just do it like this instead:
#interface Foo : Bar
#property (retain) Baz *qux;
#end
#implementation Foo
#synthesize qux;
- (void)dealloc {
[qux release];
[super dealloc];
}
#end
Then, when you want to access the instance variable directly, just say qux (which translates to self->qux in C syntax for accessing a member from a pointer). When you want to use accessors methods (which will notify observers, and do other interesting things, and make things safer and easier with respect to memory management), use self.qux ([self qux]) and self.qux = blah; ([self setQux:blah]).
The sad thing here is that Apple's sample code and template code sucks. Never use it as a guide to proper Objective-C style, and certainly never use it as a guide to proper software architecture. :)
Here is another reason. Without underscoring instance variables you frequently obtain warning with the parameters self.title = title and self.rating = rating:
#implementation ScaryBugData
#synthesize title;
#synthesize rating;
- (id)initWithTitle:(NSString *)title rating:(float)rating {
if (self = [super init]) {
self.title = title; // Warning. Local declaration hides instance variable
self.rating = rating; // Warning. Local declaration hides instance variable
}
return self;
}
#end
You avoid warning by underscoring instance variables:
#implementation ScaryBugData
#synthesize title = _title;
#synthesize rating = _rating;
- (id)initWithTitle:(NSString *)title rating:(float)rating {
if (self = [super init]) {
self.title = title; // No warning
self.rating = rating; // No warning
}
return self;
}
#end
in the application didFinishLaunchingWithOptions: method the window and viewController ivars are referred to using self
No, they're not. Those are references to the properties window and viewController. That's the point of the underscore, to make it clearer when the property is being used (no underscore) and when the ivar is being accessed directly (with underscore).
Yes, Its is just to differentiate the reference of object. That is , if the object is referred directly use it with underscore, otherwise use self to refer the object.

Objective-C Dot Syntax and Init

I have read a number of snippets that mention you should never use dot-notation within your init or dealloc methods. However, I can never seem to find out why. One post did mention in passing that it has to do with KVO, but no more.
#interface MyClass : NSObject {
SomeObject *object_;
}
#property (nonatomic, retain) SomeObject *object;
#end
This implementation is bad?
#implementation MyClass
#synthesize object = object_;
- (id)initWithObject:(SomeObject *)object {
if (self = [super init]) {
self.object = object;
}
return self;
}
#end
But this is good?
#implementation MyClass
#synthesize object = object_;
- (id)initWithObject:(SomeObject *)object {
if (self = [super init]) {
object_ = [object retain];
}
return self;
}
#end
What are the pitfalls of using dot-notation inside your init?
Firstly, it's not the dot notation specifically, it's the accessors that you shouldn't use.
self.foo = bar;
is identical to
[self setFoo: bar];
and they are both frowned upon within init/dealloc.
The main reason why is because a subclass might override your accessors and do something different. The subclass's accessors might assume a fully initialised object i.e. that all the code in the subclass's init method has run. In fact, none of it has when your init method is running. Similarly, the subclass's accessors may depend on the subclass's dealloc method not having run. This is clearly false when your dealloc method is running.
The reasons I've heard mainly crop up due to when you write your own setters/getters. When using the default #synthesized versions of the methods it won't cause much of an issue. When you write your own setter though, it is generally going to have a sideeffect on your class. This sideeffect is probably not wanted in the init, or even is going to cause issues if it references other ivars that haven't been created yet. Same issue in the dealloc, if you have a sideeffect, it has potential to blow up.

Objective-C 2.0; Assigning a Property; Leaking Memory?

I'm still learning about Objective-C memory management. I'm trying to implement several simple classes in an example program that I'm building.
As an example, say I have the following class definition:
#import <UIKit/UIKit.h>
#interface customViewController : UIViewController
{
customObject *myCustomObject;
}
#property (retain) customObject *myCustomObject;
- (void)replaceCustomObject:(customObject *)newObject;
#end
For the property, I use the standard synthesize keyword...
#synthesize myCustomObject;
Then please assume that in the instance of customViewController the myCustomObject is already set with a valid value and is in use. Then the method replaceCustomObject is defined as:
- (void)replaceCustomObject:(customObject *)newObject
{
//Does this cause a memory leak because I just assign over
//the existing property?
self.myCustomObject = newObject;
}
As the comment asks, does this leak memory? Or is this the valid way to replace a previous object with a new object?
Thank you,
Frank
As others have mentioned, your code is perfectly valid and won't leak memory when assigning to the property.
If you have forgotten to implement a proper dealloc method, the last object assigned will be leaked when your customViewController is destroyed. A proper dealloc implementation would look like so:
- (void)dealloc
{
self.myCustomObject = nil;
[super dealloc];
}
That's perfectly valid, and does not leak memory. The synthesized accessors manage retain counts correctly.
(As an aside, you don't need that replaceCustomObject: method; since your property is readwrite by default, you have an auto-generated setCustomObject: method that clients of your class can use, and which follows the normal Cocoa naming conventions.)
According to this, if you use (retain) in your declaration, the synthesized method will release the old value first, then retain the new one:
if (property != newValue) {
[property release];
property = [newValue retain];
}
the property accessor syntax
self.x = y;
has the same effect as calling the setter method explicitly:
[self setX:y];
The accessor method will do whatever it has been written to do. In your case, for a #property(retain) property that has been #synthesized, the accessor will release the old object and retain the new one.
So, calling the setter, whether explicitly or through the '.' syntax, will do the right thing - including the right memory management.
So in short: no, this will not leak memory.