I am developing an ARC enabled project. From a view controller I am pushing MyClass,
- (void)pushMyClass {
MyClass *myClass = [[MyClass alloc] init];
[self.navigationController pushViewController:myClass animated:YES];
}
After doing some operations I am popping MyClass. The problem here is that MyClass is not getting deallocated. Following is how the classes look.
/* MyHelperClassDelegate */
#protocol MyHelperClassDelegate <NSObject>
- (void)helperDidFinishHelping:(MyHelperClass *)helper;
#end
/* MyHelperClass Interface */
#interface MyHelperClass : NSObject {
__weak id <MyHelperDelegate> delegate;
}
#property(nonatomic, weak) id<MyHelperDelegate> delegate;
- (void)startHelping;
#end
/* MyHelperClass Implementation */
#implementation MyHelperClass
#synthesize delegate;
- (void)dealloc {
delegate = nil;
}
/* MyClass */
#interface MyClass : UIViewController <MyHelperClassDelegate> {
MyHelperClass *helper;
}
#implementation MyClass {
- (void)dealloc {
helper.delegate = nil;
}
- (void)getHelp {
helper = [MyHelperClass new];
helper.delegate = self;
[helper startHelping];
}
- (void)helperDidFinishHelping:(MyHelperClass *)helper {
}
}
MyHelperClass calls a web service using NSMutalbleURLRequest & NSURLConnection to fetch some data and saves it to user defaults.
One thing to notice here is, if I comment the line helper.delegate = self;, then MyClass gets deallocated.
What to do to make MyClass get deallocated when it is popped out of navigation controller?
Thanks.
Your delegate code looks correct (except your use of an ivar, you don't show a #synthesize so you may have _delegate and delegate both). Its quite likely that something else is retaining MyClass. What I suggest you do is add a NSLog to your MyClass dealloc. Then push it, and immediately hit the back button and see if its dealloc'd or not. If not, then take a hard look at what you do in viewDidLoad et al and start commenting out sections of that code until you can get the dealloc.
Also, I assume you don't keep a strong reference in the class that pushes the MyClass object.
I agree with Chuck that one cannot say much from the code provided. But one reason why the MyClass object is not deallocated might be that it is retained by your helper object since delegate is declared as strong, and the MyClass object has the property helper also declared as strong. In this case you had a retain cycle, and none of them can be released.
The trick could possibly lie within the fact that you use NSURLConnection. It is not specified how you use this class with the code that you've provided, but please note the special considerations referenced in the NSURLConnection class reference:
Special Considerations: During the download the connection maintains a
strong reference to the delegate. It releases that strong reference
when the connection finishes loading, fails, or is canceled.
Related
I want to write a custom delegate method to receive an event in one of my view controllers from another view controller. Should I use blocks here instead of delegates. Which is the preferred one ?
#protocol MyClassDelegate
-(void)doSomethingInDelegate;
#end
#interface MyClass : NSObject
#property id<MyClassDelegate> delegate;
-(void)doSomething
#end
#implementation MyClass
-(void)doSomething
{
[self.delegate doSomethingInDelegate];
}
#end
#interface MyOtherClass<MyClassDelegate> : NSObject
...
#end
#implementation MyOtherClass
-(void)doSomethingInDelegate
{
NSLog(#"Doing something in delegate");
}
#end
In most cases, if you have a very small number of delegate methods (ideally just 1), then blocks may be a good replacement. If you have several delegate methods, then blocks can become awkward.
UITableView has dozens of delegate methods between UITableViewDelegate and UITableViewDataSource. Configuring that with blocks would be unwieldy and make code reuse very difficult. If a particular way of "being the delegate" may be highly reusable (like in UITableViewController), then delegates are a much more powerful pattern.
On the other hand, if your delegate would wind up having just a single "thisActionFinished:` method, then a delegate is likely overkill and it's better to just pass a block. There are many cases that this is true, and we used to have to need to create a lot of one-method delegate protocols, and it was a bit of a pain. Blocks made that common pattern a lot easier.
But it's not a universal replacement for delegation, and blocks have many other purposes that have nothing to do with callbacks. So it's important to learn both techniques.
Looking to your specific example, there are several mistakes. Let's do it in both delegate and block forms.
Delegate
// Since the protocol needs to know about the class, you need to warn the
// compiler that this class exists.
#class MyClass;
// Declare the delegate protocol. Delegate method names should follow this
// pattern with "did", "should", or "will" in their names. Delegate methods
// should always pass the delegating object as the first parameter. A given
// delegate may be delegating for several instances.
#protocol MyClassDelegate
-(void)myClass:(MyClass *)class didSomething:(id)something;
#end
// Declare the class that has a delegate. Notice that `delegate` should be `weak`
// here. In your example, it's `strong`, and that will almost always lead to a
// retain loop. With rare exceptions, delegates are not retained.
#interface MyClass : NSObject
#property (nonatomic, readwrite, weak) id<MyClassDelegate> delegate;
-(void)doSomething;
#end
// Do the thing
#implementation MyClass
-(void)doSomething {
[self.delegate myClass:self didSomething:#"SOMETHING"];
}
#end
// The delegate object almost always has a strong pointer to the thing it delegates
// for. That's why you want the `delegate` property to be weak.
// Note that your syntax was wrong. "MyOtherClass <MyClassDelegate>". That's
// the new generic syntax, not the protocol syntax. Protocols go at the end.
#interface MyOtherClass : NSObject <MyClassDelegate>
#property (nonatomic, readwrite, strong) MyClass *c;
#end
// And the obvious impl
#implementation MyOtherClass
- (instancetype)init {
self = [super init];
if (self) {
self.c = [MyClass new];
self.c.delegate = self;
}
return self;
}
-(void)myClass:(MyClass *)class didSomething:(id)something {
NSLog(#"Doing something in delegate");
}
#end
Block
Let's do the same thing if this were a block-based API.
// If your callback takes no arguments and returns nothing, then you can
// use dispatch_block_t here. But often you need parameters or return
// something, and for that you should usually make a typealias. Welcome to the
// spiral world of block syntax.
typedef void(^MyClassCallback)(id something);
// Instead of a delegate, we have a callback. We might have several. We might
// have a block that returns the row height. But if you're doing a lot of
// that, just use a delegate. Note that blocks should always be `copy`.
#interface MyClass : NSObject
#property (nonatomic, readwrite, copy) MyClassCallback callback;
-(void)doSomething;
#end
// And here's how you use the block. It's just like a function.
#implementation MyClass
-(void)doSomething {
if (self.callback != nil) {
self.callback(#"SOMETHING");
}
}
#end
// And the delegate.
#interface MyOtherClass : NSObject
#property (nonatomic, readwrite, strong) MyClass *c;
#end
#implementation MyOtherClass
- (instancetype)init {
self = [super init];
if (self) {
self.c = [MyClass new];
// And here's the syntax for creating the block.
self.c.callback = ^(id something) {
NSLog(#"Doing something in delegate");
};
}
return self;
}
#end
Notice we don't need an extra method in the delegate just to hold one line of code, and we don't need to define a protocol. That's the big reason for the move to blocks for lightweight delegation. It keeps related code close together. But when the code gets complicated, "together" gets crazy, and blocks are not longer a good solution. Back to delegates, which do that very well.
EDIT: edited for clarity
Disclaimer: I'm new and pretty bad. But I have tried very hard and read lots of stuff to figure this out, but I have not...
I think my whole delegate pattern would work, except I can't figure out how to set the delegate property of ViewController to self in the MatchLetter class. The reason is because I can't figure out how to call code there. It's not a view controller, so viewDidLoad or prepareForSegue won't work.
This is what I've got:
ViewController.h
#import <UIKit/UIKit.h>
#class ViewController;
#protocol letterMatchProtocol <NSObject>
- (BOOL) isLetterMatch:(char) firstLetter;
#end
#interface ViewController : UIViewController
#property (nonatomic, weak) id <letterMatchProtocol> delegate;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
char c = 'a';
// This is the method I want to delegate to MatchLetter, to have a BOOL returned
BOOL returnValue = [self.delegate isLetterMatch:c];
}
#end
MatchLetter.h
#import <Foundation/Foundation.h>
#import "ViewController.h"
#interface Delegate : NSObject <letterMatchProtocol>
#end
MatchLetter.m
#import "MatchLetter.h"
#implementation Delegate
// this is the code I think I need to run here, to set the delegate property...
// ViewController *viewController = [ViewController new];
// viewController.delegate = self;
// ... so that isLetterMatch can be run here from ViewController.m
// But I don't know where to put this code, or how to get it to run before the ViewController
// especially since there are no segues or views to load.
- (BOOL) isLetterMatch:(char)firstLetter {
if (firstLetter == 'a') {
return YES;
}
else {
return NO;
}
}
#end
Can somebody please tell me the best way to proceed? Thanks for reading
You asked "Where to set delegate = self? Or should I just use a different design pattern?".
Answer: Don't. An object should never be it's own delegate.
Your code is quite a mess.
Don't name a class "Delegate". A delegate is a design pattern. The whole point of a delegate is that any object that conforms to a particular protocol ("speaks the language") can serve as the delegate. You don't need to know what class of object is serving as the delegate, but only that it speaks the language you need.
An analogy: When you call the operator, you don't care who is working the operator desk. You don't care about his/her gender, religion, ethnic background, how tall they are, etc. You just care that they speak your language.
Likewise, when you set up a delegate, it doesn't matter what type of object gets set as the delegate. All that matters is that the object that is the delegate conforms to the protocol for that delegate.
A table view can have ANY object serve as it's delegate, as long as that object conforms to the UITableViewDelegate protocol. You usually make you view controller be the table view's delegate, but you don't have to. You could create a custom class that manages your table views, and have it be the delegate. There is no "TableViewDelegate" object class. There is instead a UITableViewDelegate protocol, and any object that conforms to the protocol can act as a table view's delegate.
Edit: Your question is confusing. I think what you're proposing is that your Delegate class would create a view controller and make itself the delegate for the view controller.
If that's what you are talking about, your thinking is backwards. The view controller is using the Delegate class as a helper class. Any given instance of a view controller class can create an instance of the Delegate class and set it as it's delegate if it desires. You might have 3 instances of ViewController at one time, each with it's own instance of your Delegate class.
Thus, the ViewController object is the one that should create and set up an instance of Delegate if it needs one:
- (void) viewDidLoad;
{
self.delegate = [[Delegate alloc] init];
//other setup here
}
I feel frustrated with this problem, I my delegate doesn't work, Here's the code snippet below. I'm just using xib in this application.
//classA.h file
ClassA.h
#import "ClassB.h"
#interface ClassA : UIViewController< ClassBDelegate >
//classA.m file
**ClassA.m**
-(void)didSuccessPreview:(ClassB *)controller andLog:(NSString *)log{
NSLog(#"%#", log);
}
//classB.h file
**ClassB.h**
#import <UIKit/UIKit.h>
#class ClassB;
#protocol ClassBDelegate <NSObject>
- (void)didSuccessPreview:(ClassB *)controller andLog:(NSString *)log;
#end
#interface ClassB : UIViewController
#property (weak, nonatomic) id< ClassBDelegate >delegate;
//classB.m file
**ClassB.m**
I add this code below inside view did load
[self.delegate didSuccessPreview:self andLog:#"zz"];
I have other delegate inside my application same as the code above, but it works but this one is not, I don't know why. Inside my classA I have a button then when i click it it goes to classB, then when it goes to viewdidload in ClassB, the delegate doesn't fired.
Depending on where you assign the delegate, your code might need to look like this:
ClassB viewController = [ClassB new];
ClassA delegateStrongRef = [ClassA new]
viewController.delegate = delegateStrongRef; // <-- you are missing this now;
// Fixed: the ClassA object must be referenced strongly somewhere else
// besides the (weak)delegate property, otherwise it will be deallocated.
(The code above is the part where you create the instance of ClassB, the view controller. It might be inside the AppDelegate, another viewController's implementation, anything - depending on how your app is structured).
Then, in the view controller's -viewDidload method, you can have the delegate execute a method like this:
- (void)viewDidLoad
{
[self.delegate didSuccessPreview:self andLog:#"zz"];
}
so, at some point after instantiating your view controller, you need to assign an object of type ClassA (the class that adopts the delegate protocol) to its delegate property, otherwise it will be nil and any messages sent to it will be ignored (no method executed).
Properties and instance variables of object type are not allocated automatically, but initialized to nil (ints, floats etc, are initialized to 0, 0.0f, etc.)
EDIT: If you are assigning the delegate from ClassA's code, then it might look like this:
ClassA.m:
- (void) someMethodOfClassA
{
ClassB viewController = [ClassB new];
viewController.delegate = self;
// e.g., Do something with the view controller...
[navigationController pushViewController:viewController animated:YES];
}
Since the delegate property is defined as a weak reference, before calling any method of the delegate make sure it has not been deallocated and its reference set back to nil (use NSLog or set a breakpoint).
I´m having problems declarating my own delegate. Well...thats not exactly true: i have it declarated and, when i build the project, the compiler reports no issues. I declarated it in this way:
I made a file (enviarDatos.h) for declare the protocol:
#protocol enviarDatos <NSObject>
- (void)addItemViewController:(NSMutableArray *)item;
#end
In the Vista2.h (ViewController) file I imported the file enviarDatos.h and declared a property:
#property (nonatomic, weak) id <enviarDatos> delegare;
In the Vista2.m (ViewController) file I use the protocol method:
#interface ViewController : UIViewController <enviarDatos> {
And, finally, in the ViewController.m file I implement the delegates method:
- (void)addItemViewController:(NSMutableArray *)ar {
origen = ar;
}
Does anyone see something wrong? the code of the last function its never executing.
Thanks for your help.
EDIT:
What i need is to change an array in ViewController from Vista2 (another viewcontroller)
Then create delegate property in next view(child view) & set it to self in parent view while pushing or showing child view.
ParentView.m
1.Implement protocol methods
- (void)addItemViewController:(NSMutableArray *)ar
{
origen = ar;
}
2.While showing child view
ChildViewController *child = [[ChildViewController alloc] init];
child.delegate = self;
//present child view
ChildView.h
#property (nonatomic, weak) id <enviarDatos> delegare;
ChildView.m
-(void) anyMethod
{
if([self.delegate respondsToSelector:#selector(addItemViewController:)])
{
[self.delegate addItemViewController:mutableArray];
}
}
Ah, it looks like you are declaring the delegate property in the wrong place.
You should declare the property delegate in enviarDatos.h.
#property (nonatomic, weak) id <enviarDatos> delegate;
Then in Vista2.m you will do something like this...
EnviarDatos *myObject = [[EnviarDatos alloc] init];
myObject.delegate = self;
This then sets up the EnviarDatos object and assigns the Vista2 object as the delegate.
Now, in EnviarDatos.m you can run...
[self.delegate addItemViewController:someObjectArray];
And this will then run that code in the Vista2 object.
Delegates are used for calling back to objects that create them (or some other objects). If you create an object and then want to run a method in it then you won't need a delegate.
Can you say at what condition addItemViewController is invoked?
You seem to be on the right track, but are you sure you are setting the delegate as
[yourObject setDelegate: self];
Have you tried debugging it? Does the debugger pause at addItemViewController if you set a breakpoint there? Can you confirm the delegate is not null inside the method? I may post some code but your seems to be right except for the assigning of delegate, I think you should check it.
I need to get things clear about Objective-C memory management:
If I declare an object in the class header as ivar without #property:
#interface MyFacebooDelegate : UIViewController
{
TableViewController *tableController;
}
...
#end
and some where in the code for example in - (void)viewDidLoad I do :
tableController = [[TableViewController alloc] init];
so where is best way to release it. What if I make the instant object a property what will be the different? and how the memory management will be too
#interface MyFacebooDelegate : UIViewController
{
TableViewController *tableController;
}
...
#end
#property (nonatomic, strong) TableViewController *tableController;
What the following syntax do exactly for the object viewController:
.h
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) ViewController *viewController;
#end
.m
#implementation AppDelegate
#synthesize window = _window;
#synthesize viewController = _viewController;
- (void)dealloc
{
[_window release];
[_viewController release];
[super dealloc];
}
.....
#end
If I want to return an object through a method to another class, do I need to autorelease it in the method body first and then retain it in receiver side?
for example this method what exactly to do in the method body and in the receiver side too:
-(NSString *)getFriendId
{
NSArray *ar = [NSArray arrayWithObjects:#"1",#"2",#"3", nil];
return [ar objectAtIndex:0];
}
I know this a lot but I am really confused and need your help.
1) best way is in dealloc; or right before re-setting it.
2) a property does the retain/release for you. But WARNING! You keep mixing up things. You use "strong" here, which relates to ARC. If you really insist on using classic retain/release (you shouldn't) then use (nonatomic, retain) instead.
3) Your properties get deallocated on dealloc. Again, strong is wrong here.
4) Yes. Ideally you should. Another reason why ARC is awesome, it does this all for you, automatically.
tl;dr: Use ARC. Never go back. (But still learn manual memory management)
ARC is the answer for your all memory management question. Very import note on Strong and Weak property in addition to ,
iOS Strong property: So strong is the same as retain in a property declaration before ARC. For ARC projects I would use strong instead of retain, I would use assign for C primitive properties.
iOS outlets should be defined as declared properties. Outlets should generally be weak, except for those from File’s Owner to top-level objects in a nib file (or, in iOS, a storyboard scene) which should be strong. Outlets that you create will therefore typically be weak by default, because: Outlets that you create to, for example, subviews of a view controller’s view or a window controller’s window, are arbitrary references between objects that do not imply ownership.