Why don’t iOS classes adopt copyWithZone protocol to encourage active mem mgt? - objective-c

Recently turning to iOS after having worked with Cocoa, I was startled to get a SIGABRT with the following error: “-[UIDeviceRGBColor copyWithZone:]: unrecognized selector sent to instance…” I had called “copy” on a UIColor.
I looked at the class references and, zounds, UIColor does not adopt any protocols, in contrast to NSColor.
Now, this is not a big deal. I was just attempting to be more efficient by taking active ownership of a color instance so as to discard it immediately after use. But I thought the purpose behind Apple’s omitting a garbage collector in iOS was to encourage developers to do exactly what I was doing, to keep a lean memory profile on the memory-starved, battery-challenged portable devices.
Any ideas on Apple’s rationale, or is there some error in my assumptions?

I don't understand why you think implementing the NSCopying protocol would "encourage active memory management".
Since UIColor is immutable (it implements no methods that change its internal state), there is no point making a copy. Just retain it if you want to keep it around, and release it when you're done. There is no need for anything else.
If you really wanted, you could add copying in a category:
#implementation UIColor (Copying) <NSCopying>
- (id)copyWithZone:(NSZone *)zone
{
return [self retain];
}
#end
But obviously that doesn't actually give you any new functionality. Apparently Apple didn't think it was worth the time when they implemented that class.

My app needs to work on both iOS5 (UIColor>>#copyWithZone doesn't exist) and iOS6+ (UIColor>>#copyWithZone exists) so I came up with the following:
#implementation UIColor(ios5CopyWithZone)
+ (void)initialize
{
// iOS5 dosn't include UIColor>>#copyWithZone so add it with class_addMethod.
// For iOS6+ class_addMethod fails as UIColor>>#copyWithZone already exists.
Class klass = [UIColor class];
Method methodToInstall = class_getInstanceMethod(klass, #selector(ios5CopyWithZone:));
class_addMethod(klass, #selector(copyWithZone:), method_getImplementation(methodToInstall), method_getTypeEncoding(methodToInstall));
}
// UIImage is immutable so can just return self.
// #retain to ensure we follow mem-management conventions
-(id)ios5CopyWithZone:(NSZone *)__unused zone
{
return [self retain];
}
#end
The code attempts to adds UIColor>>#copyWithZone using the runtime's class_addMethod. I don't know if this is any better than implementing UIColor>>#copyWithZone directly in a category, however reading Apple's Avoid Category Method Name Clashes implies that it is bad practice to reimplement an existing framework method (that is UIColor>>#copyWithZone in iOS6). However I realise that +initialize could potentially trample on a framework's +initialize.

Related

Is it ever Ok to have a 'strong' reference for a delegate?

I have a class that retrieves JSON from a URL and returns the data via the protocol/delegate pattern.
MRDelegateClass.h
#import <Foundation/Foundation.h>
#protocol MRDelegateClassProtocol
#optional
- (void)dataRetrieved:(NSDictionary *)json;
- (void)dataFailed:(NSError *)error;
#end
#interface MRDelegateClass : NSObject
#property (strong) id <MRDelegateClassProtocol> delegate;
- (void)getJSONData;
#end
Note that I'm using strong for my delegate property. More about that later...
I am trying to write a 'wrapper' class that implements getJSONData in a block-based format.
MRBlockWrapperClassForDelegate.h
#import <Foundation/Foundation.h>
typedef void(^SuccessBlock)(NSDictionary *json);
typedef void(^ErrorBlock)(NSError *error);
#interface MRBlockWrapperClassForDelegate : NSObject
+ (void)getJSONWithSuccess:(SuccessBlock)success orError:(ErrorBlock)error;
#end
MRBlockWrapperClassForDelegate.m
#import "MRBlockWrapperClassForDelegate.h"
#import "MRDelegateClass.h"
#interface DelegateBlock:NSObject <MRDelegateClassProtocol>
#property (nonatomic, copy) SuccessBlock successBlock;
#property (nonatomic, copy) ErrorBlock errorBlock;
#end
#implementation DelegateBlock
- (id)initWithSuccessBlock:(SuccessBlock)aSuccessBlock andErrorBlock:(ErrorBlock)aErrorBlock {
self = [super init];
if (self) {
_successBlock = aSuccessBlock;
_errorBlock = aErrorBlock;
}
return self;
}
#pragma mark - <MRDelegateClass> protocols
- (void)dataRetrieved:(NSDictionary *)json {
self.successBlock(json);
}
- (void)dataFailed:(NSError *)error {
self.errorBlock(error);
}
#end
// main class
#interface MRBlockWrapperClassForDelegate()
#end
#implementation MRBlockWrapperClassForDelegate
+ (void)getJSONWithSuccess:(SuccessBlock)success orError:(ErrorBlock)error {
MRDelegateClass *delegateClassInstance = [MRDelegateClass new];
DelegateBlock *delegateBlock = [[DelegateBlock alloc] initWithSuccessBlock:success andErrorBlock:error];
delegateClassInstance.delegate = delegateBlock; // set the delegate as the new delegate block
[delegateClassInstance getJSONData];
}
#end
I've come to the objective-c world relatively recently (only lived in ARC times, and still coming to terms with blocks) and admittedly my understanding of memory management is on the slimmer side of things.
This code seems to work fine, but only if I have my delegate as strong. I understand that my delegate should be weak to avoid potential retain-cycles. Looking in instruments, I find that allocations do not continue to grow with continued calls. However, I believe 'best practice' is to have weak delegates.
Questions
Q1) is it ever 'ok' to have strong delegates
Q2) how could I implement the block-based wrapper leaving the delegate of the underlying class as weak delegate (ie. prevent the *delegateBlock from being deallocated before it receives the protocol methods)?
Q1 - Yes. As you point out yourself having delegate properties being weak is a recommendation to help avoid retain cycles. So there is nothing wrong per se with having a strong delegate, but if the clients of your class expect it to be weak you may cause them surprises. The better approach is to keep the delegate weak and for the server side (the class with the delegate property) to keep a strong reference internally for those periods it needs one. As #Scott points out Apple documents doing this for NSURLConnection. Of course that approach doesn't solve your issue - where you want the server to retain the delegate for you...
Q2 - Looked at from the client side the problem is how to keep a delegate alive as long as a server with a weak reference to it requires it. There is a standard solution to this problem called associated objects. In brief the Objective-C runtime essentially allows a key-collection of objects to be associated with another object, along with an association policy which states how long that association should last. To use this mechanism you just need to pick your own unique key, which is of type void * - i.e. an address. The following code outline shows how to use this using NSOpenPanel as an example:
#import <objc/runtime.h> // import associated object functions
static char myUniqueKey; // the address of this variable is going to be unique
NSOpenPanel *panel = [NSOpenPanel openPanel];
MyOpenPanelDelegate *myDelegate = [MyOpenPanelDelegate new];
// associate the delegate with the panel so it lives just as long as the panel itself
objc_setAssociatedObject(panel, &myUniqueKey, myDelegate, OBJC_ASSOCIATION_RETAIN);
// assign as the panel delegate
[panel setDelegate:myDelegate];
The association policy OBJC_ASSOCIATION_RETAIN will retain the passed in object (myDelegate) for as long as the object it is associated with (panel) and then release it.
Adopting this solution avoids making the delegate property itself strong and allows the client to control whether the delegate is retained. If you are also implementing the server you can of course provide a method to do this, maybe associatedDelegate:?, to avoid the client needing to define the key and call objc_setAssociatedObject itself. (Or you can add it to an existing class using a category.)
HTH.
It entirely depends on the architecture of your objects.
When people use weak delegates, it's because the delegate is usually some kind of "parent" object, which retains the thing that has the delegate (let's call the "delegator"). Why does it have to be a parent object? It doesn't have to be; however, in most use cases it turns out to be the most convenient pattern. Since the delegate is a parent object that retains the delegator, the delegator can't retain the delegate or it will have a retain cycle, so it holds a weak reference to the delegate.
However, that is not the only use situation. Take, for example, UIAlertView and UIActionSheet in iOS. The usual way that they are used is: inside a function, create an alert view with a message and add buttons to it, set its delegate, perform any other customization, call -show on it, and then forget it (it is not stored anywhere). It's a kind of "fire and forget" kind of mechanism. Once you show it, you don't need to retain it or anything and it will still be displayed on screen. It's possible in some cases you might want to store the alert view around so you can programmatically dismiss it, but that is rare; in the vast majority of use cases, you simply show and forget it, and just handle any delegate calls.
So in this case, the proper style would be a strong delegate, because 1) the parent object does not retain the alert view, so there is no issue with a retain cycle, and 2) the delegate needs to be kept around, so that when some button is pressed on the alert view, someone will be around to respond to it. Now, a lot of times, #2 isn't a problem because the delegate (parent object) is some kind of view controller or something that is otherwise retained by something else. But this is not always the case. For example, I can simply have a method that is not part of any view controller, which anyone can call to show an alert view, and if the user presses Yes, uploads something to the server. Since it's not part of any controller, it likely is not retained by anything. But it needs to stay around long enough until the alert view is done. So ideally the alert view should have a strong reference to it.
But as I've mentioned before, this is not always what you want for an alert view; sometimes you want to keep it around and dismiss it programmatically. In this case, you want a weak delegate or it will cause a retain cycle. So should an alert view have a strong or weak delegate? Well, the caller should decide! In some situations the caller wants strong; in others the caller wants weak. But how is this possible? The alert view delegate is declared by the alert view class, and must be declared as either strong or weak.
Fortunately, there is a solution that does let the caller decide -- a blocks-based callback. In a blocks-based API, the block essentially becomes the delegate; but the block is not the parent object. Usually the block is created in the calling class and captures self so that it can perform actions on the "parent object". The delegator (alert view in this case) always has a strong reference to the block. However, the block may have a strong or weak reference to the parent object, depending on how the block is written in the calling code (to capture a weak reference to the parent object, don't use self directly in the block, and instead, create a weak version of self outside the block, and let the block use that instead). In this way, the calling code fully controls whether the delegator has a strong or weak reference to it.
You are correct in that delegates are usually weakly referenced. However, there are use cases where a strong reference is preferred, or even necessary. Apple uses this in NSURLConnection:
During a download the connection maintains a strong reference to the delegate. It releases that strong reference when the connection finishes loading, fails, or is canceled.
An NSURLConnection instance can only be used once. After it finishes (either with failure or success), it releases the delegate, and since the delegate is readonly, it can't be (safely) reused.
You can do something similar. In your dataRetrieved and dataFailed methods, set your delegate to nil. You probably don't need to make your delegate readonly if you want to reuse your object, but you will have to assign your delegate again.
As other said it's about architecture. But I'll walk you through it with several examples:
Retry upon failure
Suppose you've made a URLSession, and are waiting for a network call you made through a viewController, sometimes it doesn't matter if it failed, but at other times it does. e.g. you're app is sending a message to another user, then you close that viewcontroller and somehow that network request fails. Do you want it to retry again? If so then that viewController has to remain in memory, so it can resubmit the request again.
Writing to disk
Another case would be when a request succeeds you may want to write something to the disk, so even after the viewcontroller has its UI updated you might still want to sync your local database with the server.
Large background tasks
The original use case for NSURLSession was to power background network task execution, large file downloads and things of that nature. You need something in memory to handle the finalization of those tasks to indicate execution is complete and the OS can sleep the app.
Associating the lifecycle of downloading large files to a certain view is a bad idea…it needs to be tied to some more stable/persistent e.g. the session itself…
Normally if I’m going to use the delegate based system rather than URLSession’s newer block-based API, I have a helper object that encapsulates all the logic necessary to handle failure and success cases that I may require that way, I don’t have to rely on a heavy VC to do the dirty works
This is answer was entirely written thanks to a conversation I had with MattS

Global Variables for Class Methods

Background
In Cocoa, Apple frequently makes use of the following paradigm:
[NSApplication sharedApplication]
[NSNotificationCenter defaultNotificationCenter]
[NSGraphicsContext currentContext]
[NSCalendar currentCalendar]
and so on.
They also will occasionally make use of a paradigm that I feel is far more legible when working with vast amounts of code.
NSApp //which maps to [NSApplication sharedApplication]
Goal
I'd love to be able to utilize this sort of global variable, both in my own classes, and in extensions to other classes.
MYClassInstance
NSDefaultNotificationCenter
NSCal /* or */ NSCurrentCalendar
and so on.
The "duh" Approach
#define. Simply #define NSCal [NSCalendar currentCalendar], but as we all know by now, macros are evil (or so they say), and it just doesn't seem like the right Cocoa way to go about this.
Apple's Approach
The only source I could find regarding NSApp was APPKIT_EXTERN id NSApp;, which is not exactly reusable code. Unless I'm mistaken, all this code does is define NSApp to be an id the world around. Unfortunately unhelpful.
Close, but not Quite
In my searches, I've managed to find several leads regarding "global constants", however things like this:
extern NSString * const StringConstant;
are unfortunately limited to compile-time constants, and cannot map to the necessary class method.
Bottom Line
I'd love to be able to roll my own NSApp-style global variables, which map to class methods like [NSNotificationCenter defaultNotificationCenter]. Is this possible? If so, how should I go about it?
Further Attempts
I'm trying to implement specifically the framework singletons in the following way:
MySingletons.h
//...
extern id NSNotifCenter;
//...
MySingletons.m
//...
+(void)initialize
{
NSNotifCenter = [NSNotificationCenter defaultCenter];
}
//...
MyAppDelegate.m
//...
#import "MySingletons.h"
//...
//in applicationDidFinishLaunching:
[MySingletons initialize];
NSLog(#"%#", NSNotifCenter);
//...
However, this results in a compile-time error where the _NSNotifCenter symbol cannot be found.
Goal!
I'm currently working on an Objective-C class to encapsulate some of the framework singletons I've referred to in this question. I'll add the GitHub information here when I get it up.
That's funny, I just made this suggestion on another question.
You just expose the variable that holds the singleton instance as a global itself. NSApp isn't actually mapping to a sharedApplication call. It's a regular old pointer; it was set up during the application launch process to point to the same instance that you would get back from that call.
Just like NSApp, you declare the variable for any file which imports the header:
extern MySingleton * MySingletonInstance;
in the header (you can use APPKIT_EXTERN if you like; the docs indicate that it just resolves to extern in ObjC anyways).
In the implementation file you define the variable. Usually the variable holding the shared instance is declared static to confine its linkage to that file. If you remove the static, the statement defines storage that is "redeclared" in the header.
Then, use it as you did before. The only caveat is that you still have to get your singleton setup method [MySingleton sharedInstance] called before the first time you use the global in order to make sure it's initialized. -applicationDidFinishLaunching: may be a good candidate for a place to do this.
As for creating pointers to framework singletons, you can just stash the result of [CocoaSingleton sharedInstance] in whatever variable you like: an ivar in a class that wants to use it, a local variable, or in a global variable that you initialize very early in your program via a function you write.
The thing is, that's not guaranteed not to cause problems. Except in the case of NSApp (or unless it's documented somewhere) there's really no guarantee that the object you get back from any given call to sharedInstance is going to remain alive, valid, or useful past the end of your call stack.
This may just be paranoia, but I'd suggest not doing this unless you can find a guarantee somewhere that the supposed singletons you're interested in always return the same instance. Otherwise, you might suddenly end up with a dangling global pointer.
Addressing your code, the declaration in your header doesn't create a variable. You still need a definition somewhere:
// MySingletons.h
// Dear compiler, There exists a variable, NSNotifCenter, whose
// storage is elsewhere. I want to use that variable in this file.
extern id NSNotifCenter;
// MySingletons.m
// Dear compiler, please create this variable, reserving memory
// as necessary.
id NSNotifCenter;
#implementation MySingletons
// Now use the variable.
// etc.
If you're creating a singleton, you might want to glance at Apple's singleton documentation.
The existing discussion here was so intriguing that I did a little research and discovered something I'd never realized before: I can #import a header file from my own project into the project's .pch file (the precompiled header). This header file becomes automatically visible to all the other class files in my project with no effort on my part.
So here's an example of what I'm now doing. In the .pch file, beneath the existing code:
#import "MyIncludes.h"
In MyIncludes.h are two kinds of thing, categories and externs (the latter in accordance with Josh's suggestion):
extern NSString* EnglishHiddenKey;
extern NSString* IndexOfCurrentTermKey;
#interface UIColor (mycats)
+ (UIColor*) myGolden;
+ (UIColor*) myPaler;
#end
In MyIncludes.m we provide definitions to satisfy all the declarations from the header file. The externs don't have to be defined from within any class:
#import "MyIncludes.h"
NSString* EnglishHiddenKey = #"englishHidden";
NSString* IndexOfCurrentTermKey = #"indexOfCurrentTerm";
#implementation UIColor (mycats)
+ (UIColor*) myGolden {
return [self colorWithRed:1.000 green:0.894 blue:0.541 alpha:.900];
}
+ (UIColor*) myPaler {
return [self colorWithRed:1.000 green:0.996 blue:0.901 alpha:1.000];
}
#end
Except for the part about using the pch file to get magical global visibility, this is not really any different from Josh's suggestion. I'm posting it as a separate answer (rather than a mere comment) because it's long and needs formatting, and the explicit code might help someone.
(Note that there is no memory management, because I'm using ARC. The externs leak, of course, but they are supposed to leak: they need to live as long as the app runs.)

Intercept method call in Objective-C

Can I intercept a method call in Objective-C? How?
Edit:
Mark Powell's answer gave me a partial solution, the -forwardInvocation method.
But the documentation states that -forwardInvocation is only called when an object is sent a message for which it has no corresponding method. I'd like a method to be called under all circumstances, even if the receiver does have that selector.
You do it by swizzling the method call. Assuming you want to grab all releases to NSTableView:
static IMP gOriginalRelease = nil;
static void newNSTableViewRelease(id self, SEL releaseSelector, ...) {
NSLog(#"Release called on an NSTableView");
gOriginalRelease(self, releaseSelector);
}
//Then somewhere do this:
gOriginalRelease = class_replaceMethod([NSTableView class], #selector(release), newNSTableViewRelease, "v#:");
You can get more details in the Objective C runtime documentation.
Intercepting method calls in Objective-C (asuming it is an Objective-C, not a C call) is done with a technique called method swizzling.
You can find an introduction on how to implement that here. For an example how method swizzling is implemented in a real project check out OCMock (an Isolation Framework for Objective-C).
Sending a message in Objective-C is translated into a call of the function objc_msgSend(receiver, selector, arguments) or one of its variants objc_msgSendSuper, objc_msgSend_stret, objc_msgSendSuper_stret.
If it was possible to change the implementation of these functions, we could intercept any message. Unfortunately, objc_msgSend is part of the Objective-C runtime and cannot be overridden.
By googling I found a paper on Google Books: A Reflective Architecture for Process Control Applications by Charlotte Pii Lunau. The paper introduces a hack by redirecting an object's isa class pointer to an instance of a custom MetaObject class. Messages that were intended for the modified object are thus sent to the MetaObject instance. Since the MetaObject class has no methods of its own, it can then respond to the forward invocation by forwarding the message to the modified object.
The paper does not include the interesting bits of the source code and I have no idea if such an approach would have side effects in Cocoa. But it might be interesting to try.
If you want to log message sends from your application code, the -forwardingTargetForSelector: tip is part of the solution.
Wrap your object:
#interface Interceptor : NSObject
#property (nonatomic, retain) id interceptedTarget;
#end
#implementation Interceptor
#synthesize interceptedTarget=_interceptedTarget;
- (void)dealloc {
[_interceptedTarget release];
[super dealloc];
}
- (id)forwardingTargetForSelector:(SEL)aSelector {
NSLog(#"Intercepting %#", NSStringFromSelector(aSelector));
return self.interceptedTarget;
}
#end
Now do something like this:
Interceptor *i = [[[Interceptor alloc] init] autorelease];
NSFetchedResultsController *controller = [self setupFetchedResultsController];
i.interceptedTarget = controller;
controller = (NSFetchedResultsController *)i;
and you will have a log of message sends. Note, sends sent from within the intercepted object won't be intercepted, as they will be sent using the original object 'self' pointer.
If you only want to log messages called from the outside (usually called from delegates; to see which kind of messages, when, etc.), you can override respondsToSelector like this:
- (BOOL)respondsToSelector:(SEL)aSelector {
NSLog(#"respondsToSelector called for '%#'", NSStringFromSelector(aSelector));
// look up, if a method is implemented
if([[self class] instancesRespondToSelector:aSelector]) return YES;
return NO;
}
Create a subclass of NSProxy and implement -forwardInvocation: and -methodSignatureForSelector: (or -forwardingTargetForSelector:, if you're simply directing it on to a second object instead of fiddling with the method yourself).
NSProxy is a class designed for implementing -forwardInvocation: on. It has a few methods, but mostly you don't want them to be caught. For example, catching the reference counting methods would prevent the proxy from being deallocated except under garbage collection. But if there are specific methods on NSProxy that you absolutely need to forward, you can override that method specifically and call -forwardInvocation: manually. Do note that simply because a method is listed under the NSProxy documentation does not mean that NSProxy implements it, merely that it is expected that all proxied objects have it.
If this won't work for you, provide additional details about your situation.
Perhaps you want NSObject's -forwardInvocation method. This allows you to capture a message, retarget it and then resend it.
You can swizzle the method call with one of your own, which does whatever you want to do on "interception" and calls through to the original implementation. Swizzling is done with class_replaceMethod().
A method call, no. A message send, yes, but you're going to have to be a lot more descriptive if you want a good answer as to how.
To do something when a method is called, you could try an events based approach. So when the method is called, it broadcasts an event, which is picked up by any listeners. I'm not great with objective C, but I just figured out something similar using NSNotificationCenter in Cocoa.
But if by "intercept" you mean "stop", then maybe you need more logic to decide wether the method should be called at all.

Double releasing when it shouldn't be happening

I am really puzzled by this. I believe I am managing memory the correct way but executing the code suggests that I am double releasing the object. Here is the code and then I'll explain what is happening.
#protocol SomeDelegate <NSObject>
#required
- (id)initWithCols:(NSUInteger)Cols Rows:(NSUInteger)Rows;
#end
#interface SomeObject : NSObject <SomeDelegate> {
}
- (id)initWithCols:(NSUInteger)Cols Rows:(NSUInteger)Rows;
#end
#interface Layout : UIView {
id<SomeDelegate> someDelegate;
}
#property(retain) id<SomeDelegate> someDelegate;
- (id)initWithFrame:(CGRect)aRect Cols:(NSUInteger)Cols Rows:(NSUInteger)Rows;
#end
#implementation Layout
#synthesize someDelegate;
- (id)initWithFrame:(CGRect)aRect Cols:(NSUInteger)Cols Rows:(NSUInteger)Rows {
if(self = [super initWithFrame:aRect]) {
cols = Cols;
rows = Rows;
id<SomeDelegate> delegate = [[SomeObject alloc] initWithCols:cols Rows:rows];
[self setSomeDelegate:delegate];
//[delegate release];
}
return self;
}
-(void)dealloc {
[someDelegate release];
[super dealloc];
}
#end
Now when I uncomment out the "//[delegate release];" line in the constructor of the Layout class, then I get a "EXC_BAD_ACCESS" error and the application crashes when it attempts to dealloc. I have traced the crash to the release of the someDelegate object in the dealloc method of Layout class. If I leave it commented then the application works fine.
Can someone please explain why this is happening as it appears to be going against everything I have read about memory management in Objective-C.
Just a note that the code example actually works, however my code doesn't which follows the example. Could there be something inside of my actual SomeObject that is causing an autorelease?
Thanks in advance.
First, go back and reread the memory management rules just to make sure you are not missing anything obvious in your use of delegate elsewhere.
Next, turn on NSZombieEnabled (in your executable settings, Arguments panel, add an environment variable NSZombieEnabled set to YES).
Then add a dealloc method to your delagate if it does not have one already (make sure you call [super dealloc]!) and put a break point on there - that will tell you when your delagate is deallocated which will tell you when it is being released.
Alternatively, add trivial release/autorelease methods to your delegate class which do nothing but call through, and then breakpoint them and that will tell you exactly when it is being released.
Three final comments: in the standard naming convention for Objective C/Cocoa, you should have lowercase parameter fields, ie it should be:
- (id)initWithFrame:(CGRect)aRect cols:(NSUInteger)Cols rows:(NSUInteger)Rows;
When your ivar and property are named identically, it is very easy to accidently use the wrong one, so I recommend using a different ivar name and property name to avoid confusion, either use an _ prefix like Apple, or some other prefix to avoid confusion with Apple as well:
id<SomeDelegate> _someDelegate;
#synthesize someDelegate = _someDelegate;
And Apple recomends against using setters/getters in init/dealloc, so your init code should be:
_someDelegate = [[SomeObject alloc] initWithCols:cols Rows:rows];
As alluded to in the comments, the problem does not appear to be in the code posted.
I could ask for more information, but I'm firmly in the teach a man to fish camp....
A crash in -release will often be misleading in that various optimizations -- tail call optimizations, generally -- will make it look like the crash happened a frame or two above the actual call that crashed. When the crash happens, there isn't enough info on the stack to really identify the culprit.
Whenever you suspect you have any kind of a crash in -release or -dealloc, immediately turn on Zombies. This can be done through Instruments or via an environment variable or by calling a function in the Foundation very early in your program's execution.
Search for "Zombies" or "NSZombie" in the documentation included with the development environment (that'd be more of the "teach a man to fish" thing).
The problem was a MutableArray deep in a subclass that was created through a factory (autoreleased) but I was also releasing too. Unfortunately the crash wouldn't indicate which inherited dealloc was causing the crash and just stop on the first overridden dealloc.
The Zombie thing helped a little in that it told me an array was the culprit but not much else. I think there is more to NSZombie and requires more experience to take full advantage of it.

how to block a superclass method to be called to a subclass

I'm extending the functionality of a class with a subclass, and I'm doing some dirty stuff that make superclass methods dangerous (app will hang in a loop) in the context of the subclass. I know it's not a genius idea, but I'm going for the low-hanging fruit, right now it's gonna save me some time. Oh it's a dirty job, but someone's gotta do it.
Bottom line, I need to either block that method from outside, or throw an exception when it's called directly to the superclass. (But I still use it from the subclass, except with care).
What would be the best way to do this?
UPDATE ---
So this is what I went for. I'm not self-answering, as Boaz' answer mentions multiple valid ways to do this, this is just the way that suited me. In the subclass, I overrode the method like this:
- (int)dangerousMethod
{
[NSException raise:#"Danger!" format:#"Do not call send this method directly to this subclass"];
return nil;
}
I'm marking this as answered, but evidently that doesn't mean it's closed, further suggestions are welcome.
Just re-implement the unsafe method in your subclass and have it do nothing or throw an exception or re-implement it as safe, just as long as the new implementation doesn't call the unsafe superclass method.
For the C++ crew in here: Objective C doesn't let you mark methods as private. You can use its category system to split up the interface into separate files (thus hiding 'private' ones), but all methods on a class are public.
You can override whichever methods you want to block in your subclass's .h file. You can make dangerousMethod unavailable by placing the following in your .h file.
- (int)dangerousMethod __attribute__((unavailable("message")));
This will make the dangerousMethod method unavailable to anyone using your subclass.
To keep other code from using the superclass's version this method, you can further restrict by putting this in your .m file.
- (int)dangerousMethod
{
return nil;
}
note: I'm ObjC/Cocoa newcomer:
#implementation MyClass
-(void)myMethod:(NSString *)txt{
if([self class] != [MyClass class]) return;
NSLog(#"Hello");
}
#end
Peter
This article explains how to create private variables in Objective C. They aren't truly private, but from what I read, the compiler will throw a warning if you try to call them from the subclass.
If you create the methods in your superclass as "private" then the subclass has no possible way of calling them. I'm not familiar with Objective C, but every other object oriented language I've seen has the "private" qualifier.