Discussion:
Mysterious crash with NSTableView
Andreas Falkenhahn
2016-08-26 15:15:39 UTC
Permalink
Does anybody have an idea why the following code causes a "Segmentation fault" and thus
an immediate program termination? Interestingly, the code runs just fine and the
NSTableView appears correctly and is functional. The "Segmentation fault" occurs when
buttonPressed() is left and control returns to the main run loop. Thus, I suspect that
the error is probably related to autoreleasing, e.g. releasing a resource twice or
something. But I don't really see anything that's wrong with my code. Sometimes I also
get this message instead of the segmentation fault:

[NSRectSet tableView:objectValueForTableColumn:row:]:unrecognized selector sent to instance 0x100153060

But most of the time it just crashes with a segmentation fault. The code itself is
really simple and straightforward, here it is:

- (void)buttonPressed
{
NSRect rect = NSMakeRect(100, 100, 320 + 2 * 20, 78 + 200 + 20);

NSWindow *win = [[NSWindow alloc] initWithContentRect:rect styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:NO];

id listDelegate = [[MyListDelegate alloc] init];

NSScrollView *scrollview = [[NSScrollView alloc] initWithFrame:NSMakeRect(20, 52, rect.size.width - 2 * 20, 200)];
NSTableView *tableview = [[NSTableView alloc] initWithFrame:NSMakeRect(0, 0, rect.size.width - 2 * 20 - 16, 200)];
NSTableColumn *column = [[NSTableColumn alloc] initWithIdentifier:@"Column"];

[tableview addTableColumn:column];
[tableview setDelegate:listDelegate];
[tableview setDataSource:listDelegate];
[scrollview setDocumentView:tableview];
[[win contentView] addSubview:scrollview];
[scrollview release];
[tableview release];
[column release];

id buttonDelegateOK = [[MyButtonDelegate alloc] init];
NSButton *ok = [[NSButton alloc] initWithFrame:NSMakeRect(rect.size.width - 82 - 14, 12, 82, 32)];
[ok setTitle:@"OK"];
[ok setButtonType:NSMomentaryPushInButton];
[ok setBezelStyle:NSRoundedBezelStyle];
[ok setKeyEquivalent:@"\r"];
[ok setTarget:buttonDelegateOK];
[ok setAction:@selector(buttonPressed)];
[[win contentView] addSubview:ok];
[ok release];

[NSApp runModalForWindow:win];

[win orderOut:nil];
[win release];

[listDelegate release];
[buttonDelegateOK release];
}

-----------------------------------------------------------------------------------------------

The list delegate is also minimal and looks like this:

@interface MyListDelegate : NSObject
@end

@implementation MyListDelegate
- (int)numberOfRowsInTableView:(NSTableView *)_tableView
{
return 3;
}

- (id)tableView:(NSTableView *)_tableView objectValueForTableColumn:(NSTableColumn *) tableColumn row:(int)row
{
return @"Foobar";
}
@end

-----------------------------------------------------------------------------------------------

I've already spent several hours trying to find out why this particular code results
in a "Segmentation fault" but I just don't see it.

Can anybody help? Thanks in advance!

Full minimal demo program is attached for reference.
--
Best regards,
Andreas Falkenhahn mailto:***@falkenhahn.com
Gary L. Wade
2016-08-26 15:35:53 UTC
Permalink
Try clearing your table view's data source and delegate before releasing their object. It appears the pointer gets reassigned to an NSRectSet before your table view completely goes away but after its delegate and data source have.
--
Gary L. Wade (Sent from my iPad)
http://www.garywade.com/
Post by Andreas Falkenhahn
Does anybody have an idea why the following code causes a "Segmentation fault" and thus
an immediate program termination? Interestingly, the code runs just fine and the
NSTableView appears correctly and is functional. The "Segmentation fault" occurs when
buttonPressed() is left and control returns to the main run loop. Thus, I suspect that
the error is probably related to autoreleasing, e.g. releasing a resource twice or
something. But I don't really see anything that's wrong with my code. Sometimes I also
[NSRectSet tableView:objectValueForTableColumn:row:]:unrecognized selector sent to instance 0x100153060
But most of the time it just crashes with a segmentation fault. The code itself is
- (void)buttonPressed
{
NSRect rect = NSMakeRect(100, 100, 320 + 2 * 20, 78 + 200 + 20);
NSWindow *win = [[NSWindow alloc] initWithContentRect:rect styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:NO];
id listDelegate = [[MyListDelegate alloc] init];
NSScrollView *scrollview = [[NSScrollView alloc] initWithFrame:NSMakeRect(20, 52, rect.size.width - 2 * 20, 200)];
NSTableView *tableview = [[NSTableView alloc] initWithFrame:NSMakeRect(0, 0, rect.size.width - 2 * 20 - 16, 200)];
[tableview addTableColumn:column];
[tableview setDelegate:listDelegate];
[tableview setDataSource:listDelegate];
[scrollview setDocumentView:tableview];
[[win contentView] addSubview:scrollview];
[scrollview release];
[tableview release];
[column release];
id buttonDelegateOK = [[MyButtonDelegate alloc] init];
NSButton *ok = [[NSButton alloc] initWithFrame:NSMakeRect(rect.size.width - 82 - 14, 12, 82, 32)];
[ok setButtonType:NSMomentaryPushInButton];
[ok setBezelStyle:NSRoundedBezelStyle];
[ok setTarget:buttonDelegateOK];
[[win contentView] addSubview:ok];
[ok release];
[NSApp runModalForWindow:win];
[win orderOut:nil];
[win release];
[listDelegate release];
[buttonDelegateOK release];
}
-----------------------------------------------------------------------------------------------
@interface MyListDelegate : NSObject
@end
@implementation MyListDelegate
- (int)numberOfRowsInTableView:(NSTableView *)_tableView
{
return 3;
}
- (id)tableView:(NSTableView *)_tableView objectValueForTableColumn:(NSTableColumn *) tableColumn row:(int)row
{
}
@end
-----------------------------------------------------------------------------------------------
I've already spent several hours trying to find out why this particular code results
in a "Segmentation fault" but I just don't see it.
Can anybody help? Thanks in advance!
Full minimal demo program is attached for reference.
--
Best regards,
<main.m>
_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net

This email sent to ***@ml-in.
Andreas Falkenhahn
2016-08-26 15:42:30 UTC
Permalink
Post by Gary L. Wade
Try clearing your table view's data source and delegate before
releasing their object. It appears the pointer gets reassigned to an
NSRectSet before your table view completely goes away but after its delegate and data source have.
Great, that solves it. Thanks a lot!

But once again, I think it's a crime that there is no mentioning of this in the class
documentation of "setDelegate" and "setDatasource" :(
--
Best regards,
Andreas Falkenhahn mailto:***@falkenhahn.com

_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net

Th
Gary L. Wade
2016-08-26 15:52:20 UTC
Permalink
You would not see this if you hid or removed the table view first since it would not need its data source or delegate then. Try going with ARC or at least use autorelease on your delegate/data source.
--
Gary L. Wade (Sent from my iPad)
http://www.garywade.com/
Post by Andreas Falkenhahn
Post by Gary L. Wade
Try clearing your table view's data source and delegate before
releasing their object. It appears the pointer gets reassigned to an
NSRectSet before your table view completely goes away but after its delegate and data source have.
Great, that solves it. Thanks a lot!
But once again, I think it's a crime that there is no mentioning of this in the class
documentation of "setDelegate" and "setDatasource" :(
--
Best regards,
_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net

This email sent to gegs
Andreas Falkenhahn
2016-08-26 16:38:17 UTC
Permalink
Post by Gary L. Wade
You would not see this if you hid or removed the table view first
since it would not need its data source or delegate then. Try going
with ARC or at least use autorelease on your delegate/data source.
I'm not using autorelease on the delegate/data source on purpose because
AFAIU autoreleased objects are (potentially) killed whenever the application
is in an event loop and this is the case with runModalForWindow(). AFAIU
if I used autorelease on the delegate/data source then both would be
killed in the run loop started by runModalForWindow() because both setDelegate()
and setDatasource() don't retain. So using autorelease doesn't make sense
to me here. Is this right or did I get anything wrong here?
--
Best regards,
Andreas Falkenhahn mailto:***@falkenhahn.com

_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.na
Gary L. Wade
2016-08-26 17:25:27 UTC
Permalink
I'm talking about exchanging release for autorelease on your list delegate, which happens after runModal finishes. Since you now do an orderOut, your table view should not need its data source/delegate, so it should be safe keeping them set and using an autorelease, but clearing them is the safest.

This kind of exercise in understanding the MRC rules is precisely why ARC was created. If you need to use MRC, you probably should do what lots of others did and draw lots of pictures in timeframes with tally counts on objects to understand what happens when. If you go with ARC, this clearing should happen for you—I'm pretty sure the data source and delegate are weak, but I don't have the headers in front of me right now.
--
Gary L. Wade (Sent from my iPhone)
http://www.garywade.com/
Post by Andreas Falkenhahn
Post by Gary L. Wade
You would not see this if you hid or removed the table view first
since it would not need its data source or delegate then. Try going
with ARC or at least use autorelease on your delegate/data source.
I'm not using autorelease on the delegate/data source on purpose because
AFAIU autoreleased objects are (potentially) killed whenever the application
is in an event loop and this is the case with runModalForWindow(). AFAIU
if I used autorelease on the delegate/data source then both would be
killed in the run loop started by runModalForWindow() because both setDelegate()
and setDatasource() don't retain. So using autorelease doesn't make sense
to me here. Is this right or did I get anything wrong here?
--
Best regards,
_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.
Kyle Sluder
2016-08-26 18:12:55 UTC
Permalink
Post by Gary L. Wade
I'm talking about exchanging release for autorelease on your list
delegate, which happens after runModal finishes. Since you now do an
orderOut, your table view should not need its data source/delegate, so it
should be safe keeping them set and using an autorelease, but clearing
them is the safest.
Neither autorelease nor release on its own is sufficient here; Andreas
should clear out his delegates. This is true either in ARC or non-ARC,
whether the delegate property is declared `unsafe_unretained` (née
`assign`) or `weak`.

You don’t know when an object will be deallocated. While it would be
unexpected (and arguably an error) for NSTableView to hand off its
delegate to something that will take a long-lived strong +1 reference to
it, it is perfectly legal for the delegate to wind up in the autorelease
pool for an indefinite period of time. Delegates are most likely not
written to handle being called in that limbo state where they’re still
alive and assigned to the delegate property, but the object that created
them has disavowed them by releasing its last strong reference to them.

`weak` prevents retain cycles. It does not ensure program correctness.
Post by Gary L. Wade
This kind of exercise in understanding the MRC rules is precisely why ARC
was created. If you need to use MRC, you probably should do what lots of
others did and draw lots of pictures in timeframes with tally counts on
objects to understand what happens when. If you go with ARC, this
clearing should happen for you—I'm pretty sure the data source and
delegate are weak, but I don't have the headers in front of me right now.
Automatic clearing of zeroing weak references is dependent on the
*implementor* being compiled with ARC. Non-ARC clients will still see
another object’s zeroing weak ref go to nil when the last strong ref to
the referent is released.

Here’s some sample code:

/* WeakRefHolder.h
* This file is transcluded twice: once with ARC enabled, once with ARC
disabled.
*/
#import <Foundation/NSObject.h>

@interface WeakRefHolder : NSObject

@property(weak) id weakRef;

@end
/* WeakRefHolder.m
* clang -c -o WeakRefHolder.o -fobjc-arc WeakRefHolder.m
*/

#if !__has_feature(objc_arc)
#error WeakRefHolder implementation must be compiled with ARC
#endif

#import "WeakRefHolder.h"

@implementation WeakRefHolder
// Automatically synthesize implementation of .weakRef property
@end

/* main.m
* Compile: clang -o main -framework Foundation -fno-objc-arc main.m
WeakRefHolder.o
*/

#if __has_feature(objc_arc)
#error Main file should not be compiled with ARC
#endif

#import "WeakRefHolder.h"
#import <stdio.h>

@interface SquealOnDealloc : NSObject
@end

@implementation SquealOnDealloc
- (void)dealloc {
printf("<%p> deallocating!\n", self);
[super dealloc];
}
@end

int main(int argc, char **argv)
{
WeakRefHolder *holder = [[WeakRefHolder alloc] init];
id referent;
@autoreleasepool {
printf(">> Pushing autorelease pool\n");
referent = [[SquealOnDealloc alloc] init];
printf(" Assigning <%p> to .weakRef property\n",
referent);
holder.weakRef = [referent autorelease];
printf("<< Popping autorelease pool\n");
}

printf(".weakRef = %p\n", holder.weakRef);
return 0;
}

--Kyle Sluder
Post by Gary L. Wade
--
Gary L. Wade (Sent from my iPhone)
http://www.garywade.com/
Post by Andreas Falkenhahn
Post by Gary L. Wade
You would not see this if you hid or removed the table view first
since it would not need its data source or delegate then. Try going
with ARC or at least use autorelease on your delegate/data source.
I'm not using autorelease on the delegate/data source on purpose because
AFAIU autoreleased objects are (potentially) killed whenever the application
is in an event loop and this is the case with runModalForWindow(). AFAIU
if I used autorelease on the delegate/data source then both would be
killed in the run loop started by runModalForWindow() because both setDelegate()
and setDatasource() don't retain. So using autorelease doesn't make sense
to me here. Is this right or did I get anything wrong here?
--
Best regards,
_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.nark
Andreas Falkenhahn
2016-08-26 18:39:03 UTC
Permalink
Post by Kyle Sluder
Post by Gary L. Wade
I'm talking about exchanging release for autorelease on your list
delegate, which happens after runModal finishes. Since you now do an
orderOut, your table view should not need its data source/delegate, so it
should be safe keeping them set and using an autorelease, but clearing
them is the safest.
Neither autorelease nor release on its own is sufficient here; Andreas
should clear out his delegates.
So should I also clear the button delegates or is NSTableView an exception
here?

Side note:

What I find really weird in this whole thing is the fact that it crashed
although the delegates are clearly released *after* the window. I wouldn't
be surprised to get crashes if I released the delegates *before* the window.
That would be natural behaviour but from a logical point of view it's really
weird to see it crash with the delegate/data source being released *after*
the window, i.e. when one would expect NSTableView to have been fully deallocated
already.

From a logical point of view I'd expect this call

[win release];

to kill off the NSTableView and its associates completely. So I'd consider
it safe to release the delegate/data source after that, but apparently they
need to be cleared out before. It's good to know but from a logical point
of view I still think it's weird. I mean, who the heck is referencing those
delegates after the call to [win release]? Everything should be gone by
that call but there's probably some advanced wizardry going on that I'm
unaware of.
--
Best regards,
Andreas Falkenhahn mailto:***@falkenhahn.com


_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in
Quincey Morris
2016-08-26 20:06:34 UTC
Permalink
Post by Andreas Falkenhahn
From a logical point of view I'd expect this call
[win release];
to kill off the NSTableView and its associates completely. So I'd consider
it safe to …
Welcome to the latest episode of “It’s Deja Vu All Over Again!”. We used to have these sorts of discussions on this list all the time, until ARC, at which point they pretty much stopped.

Reasoning about retain counts is extremely difficult, and common sense will lead you astray.

In particular, you’re confusing “release” with “deallocate”, which is something we all did back in the days when we didn’t use ARC. The concept of releasing the “last” reference to an object, the “one” that’s “keeping it alive” is going to get you in all sorts of trouble.
Post by Andreas Falkenhahn
I mean, who the heck is referencing those delegates after the call to [win release]?
A careful reading of the documentation will tell you that windows are managed by a window manager process that’s separate from yours. It will keep windows alive until it gets a chance to remove them from its own data structures, which may not happen until the next iteration of your run loop.

But even if that weren’t true, the assumption that the table view object won’t outlive the window object is invalid.

_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net

This em
Jens Alfke
2016-08-26 20:52:35 UTC
Permalink
Post by Andreas Falkenhahn
But once again, I think it's a crime that there is no mentioning of this in the class
documentation of "setDelegate" and "setDatasource" :(
In the Xcode 8 docs for NSTableView.dataSource, it does:
"Note that in versions of OS X prior to v10.12, the table view did not retain the data source in a managed memory environment."

I’m sure I won’t be the first person to suggest that you switch to ARC. If you find ref-counting confusing, ARC will help you a lot.

—Jens
_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.
Doug Hill
2016-08-26 21:58:29 UTC
Permalink
Post by Jens Alfke
Post by Andreas Falkenhahn
But once again, I think it's a crime that there is no mentioning of this in the class
documentation of "setDelegate" and "setDatasource" :(
"Note that in versions of OS X prior to v10.12, the table view did not retain the data source in a managed memory environment."
I’m sure I won’t be the first person to suggest that you switch to ARC. If you find ref-counting confusing, ARC will help you a lot.
—Jens
As usual, Jens speaks truthfully about using ARC.

However, in your case I wonder what the static analyzer in Xcode tells you about the bug you see? Can it catch the bug? In manual ref-counting, the analyzer has saved my skin more than once. :)

Doug
_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net
Sandor Szatmari
2016-08-27 03:44:27 UTC
Permalink
Doug,
Post by Doug Hill
Post by Jens Alfke
Post by Andreas Falkenhahn
But once again, I think it's a crime that there is no mentioning of this in the class
documentation of "setDelegate" and "setDatasource" :(
"Note that in versions of OS X prior to v10.12, the table view did not retain the data source in a managed memory environment."
I’m sure I won’t be the first person to suggest that you switch to ARC. If you find ref-counting confusing, ARC will help you a lot.
—Jens
As usual, Jens speaks truthfully about using ARC.
However, in your case I wonder what the static analyzer in Xcode tells you about the bug you see?
I believe Andreas mentioned he does not use Xcode as his product is cross platform, but this is a good suggestion.

Andreas,

If you add a static analysis phase to your Makefile does it help highlight these issues?

http://clang-analyzer.llvm.org

Sandor Szatmari
Post by Doug Hill
Can it catch the bug? In manual ref-counting, the analyzer has saved my skin more than once. :)
Doug
_______________________________________________
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
https://lists.apple.com/mailman/options/cocoa-dev/admin.szatmari.net%40gmail.com
_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narki
Jeff Szuhay
2016-08-27 04:20:58 UTC
Permalink
Post by Sandor Szatmari
Post by Doug Hill
However, in your case I wonder what the static analyzer in Xcode tells you about the bug you see?
I believe Andreas mentioned he does not use Xcode as his product is cross platform, but this is a good suggestion.
Any why not?

Sure, build it without Xcode, but couldn’t you create a shell project where the product doesn’t really matter, then build and use the tools in Xcode?

_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net

This email sent to
Doug Hill
2016-08-27 05:46:26 UTC
Permalink
Post by Jeff Szuhay
Post by Sandor Szatmari
Post by Doug Hill
However, in your case I wonder what the static analyzer in Xcode tells you about the bug you see?
I believe Andreas mentioned he does not use Xcode as his product is cross platform, but this is a good suggestion.
Any why not?
Sure, build it without Xcode, but couldn’t you create a shell project where the product doesn’t really matter, then build and use the tools in Xcode?
I believe you can also invoke the analyzer via the command-line tools.
_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net

This email sent to ***@ml-
Greg Parker
2016-08-27 08:17:19 UTC
Permalink
Post by Doug Hill
Post by Jeff Szuhay
Post by Sandor Szatmari
Post by Doug Hill
However, in your case I wonder what the static analyzer in Xcode tells you about the bug you see?
I believe Andreas mentioned he does not use Xcode as his product is cross platform, but this is a good suggestion.
Any why not?
Sure, build it without Xcode, but couldn’t you create a shell project where the product doesn’t really matter, then build and use the tools in Xcode?
I believe you can also invoke the analyzer via the command-line tools.
If your build system runs from the command line and honors the CC and CXX environment variables then you may be able to use the scan-build tool to run the clang static analyzer.
http://clang-analyzer.llvm.org/scan-build.html
--
Greg Parker ***@apple.com Runtime Wrangler



_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net
Alex Zavatone
2016-08-27 16:10:54 UTC
Permalink
Sent from my iPad. Please pardon typos.
Post by Andreas Falkenhahn
Post by Gary L. Wade
Try clearing your table view's data source and delegate before
releasing their object. It appears the pointer gets reassigned to an
NSRectSet before your table view completely goes away but after its delegate and data source have.
Great, that solves it. Thanks a lot!
But once again, I think it's a crime that there is no mentioning of this in the class
documentation of "setDelegate" and "setDatasource" :(
Agrees as it SHOULD be understood by the programmer as "well, that is simply how part of Objective-C works so I should EXPECT to have to set them."

Buuut, to the mind of the person learning this or trying to fit all the complexity of learning this in their head, it might be wise in the docs to remind the programmer that they need to do this and why with a, "just in case you are assuming that your code is ready to function now, please remember that the objects that end up making a working tableView require that the tableView's dataSource object and delegate object need to be assigned, generally to the hosting view controller's instance of self. If this causes you to raise an eyebrow in confusion, the reasons why you must do this are xxx and yyyy. Likewise upon deallocation of the tableView (if it gets called), these objects will need to be set to nil after zzzz but before the tableView object is able to dispose of itself."

Please feel free to use this as a running start on an addition to the docs that actually explains to the programmer how they will most likely set up their tableView.

- Alex Zavatone
Post by Andreas Falkenhahn
--
Best regards,
_______________________________________________
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
https://lists.apple.com/mailman/options/cocoa-dev/zav%40mac.com
_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net

This email sent to ***@ml-in.narkive.ne
Andreas Falkenhahn
2016-08-27 20:55:29 UTC
Permalink
Post by Alex Zavatone
Buuut, to the mind of the person learning this or trying to fit all
the complexity of learning this in their head, it might be wise in
the docs to remind the programmer that they need to do this and why
with a, "just in case you are assuming that your code is ready to
function now, please remember that the objects that end up making a
working tableView require that the tableView's dataSource object
and delegate object need to be assigned, generally to the hosting
view controller's instance of self. If this causes you to raise an
eyebrow in confusion, the reasons why you must do this are xxx and
yyyy. Likewise upon deallocation of the tableView (if it gets
called), these objects will need to be set to nil after zzzz but
before the tableView object is able to dispose of itself."
Huh? "Remember that you have to set this property to nil before you
release the object" would already be sufficient...

By the way, I still don't know whether setting the delegate to nil
before release is a general rule or does it only apply to NSTableView?
Should I also set my button delegates to nil before the buttons are
released?
--
Best regards,
Andreas Falkenhahn mailto:***@falkenhahn.com

_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net

This ema
Quincey Morris
2016-08-27 21:54:08 UTC
Permalink
Post by Andreas Falkenhahn
I still don't know whether setting the delegate to nil
before release is a general rule or does it only apply to NSTableView?
It’s not clear what delegate you mean by “button delegate”, but it doesn’t really matter. Delegates are not a special case of the rules, just a case where you need to pay attention to what the rules imply.

A “delegate” property is “strong”, “zeroing weak” or “unsafe”. (The terminology or syntax keyword for each of these has varied over time and context.) If it’s strong or zeroing-weak, there’s no need to set the property to nil. If it’s unsafe, you generally should set it to nil before you allow the lifetime of the delegate object to end.

Therefore, you can look in the API for the property — definitively, in the SDK you’re building against — and determine which of the above ownership types the property uses.

Note that you will see some inconsistencies in ownership types in different parts of Cocoa. That’s because the delegate pattern was standardized somewhere around 10.5, but older APIs may have been different and cannot be changed without breaking source and/or run-time compatibility.

There are a few real exceptions, which are historical relics, and documented (I think) in the ARC transition guide:

— ARC-compatible ownership rules are supported back to (something like) 10.5, but zeroing weak pointers weren’t supported until (IIRC) 10.6.8. In the interim, zero weak properties were actually unsafe.

— A very few classes (NSWindowController was one of them) did not support the zeroing weak mechanism (I mean pointers to objects of these classes, not references within these classes to objects of other classes). I believe these have all been corrected now, but you might need to be aware of which OS version they changed in, if you’re supporting older deployment targets. Or, avoid depending on the zeroing part of the behavior.

Incidentally, while it might be a noble goal to have your software support OS versions all the way back to 10.6 or 10.5, there are good reasons for moving on to later deployment targets. OS X really has gotten better over the years, and way-back support starts to become more a source of bugs than a source of compatibility.

Lastly, I may have lost track of things during the series of threads we’ve had about memory management in your app, but I can’t now understand why you don’t adopt ARC. I guess I thought it was because you were maintaining existing code, which presumably did its manual memory management properly. But if you’re writing new code, or even updating old code, there is literally no downside (AFAIK) in switching to ARC. Isn’t it a positive upside in source files shared between Mac and other platforms of your app, to not need retain and release calls? Note also that ARC and manual memory management can be intermixed in the same target freely (though not in the same source file), provided the existing manual memory management does follow the rules.

Since you’re not 100% familiar with the rules, why not just switch to ARC?

_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net

Th
Andreas Falkenhahn
2016-08-29 13:37:31 UTC
Permalink
Post by Andreas Falkenhahn
I still don't know whether setting the delegate to nil
before release is a general rule or does it only apply to NSTableView?
It’s not clear what delegate you mean by “button delegate”, but it
doesn’t really matter.
Oops, I meant the button target as Kyle has already pointed out.
Post by Andreas Falkenhahn
Incidentally, while it might be a noble goal to have your software
support OS versions all the way back to 10.6 or 10.5
Just 10.6 for x86. 10.4 for PowerPC but the PowerPC version of my
app uses Carbon anyway.
Post by Andreas Falkenhahn
Lastly, I may have lost track of things during the series of
threads we’ve had about memory management in your app, but I can’t
now understand why you don’t adopt ARC. I guess I thought it was
because you were maintaining existing code, which presumably did its
manual memory management properly. But if you’re writing new code,
or even updating old code, there is literally no downside (AFAIK) in
switching to ARC. Isn’t it a positive upside in source files shared
between Mac and other platforms of your app, to not need retain and
release calls? Note also that ARC and manual memory management can
be intermixed in the same target freely (though not in the same
source file), provided the existing manual memory management does follow the rules.
Since you’re not 100% familiar with the rules, why not just switch to ARC?
The actual Cocoa code in my app is really just a few kilobytes. It's
not complicated at all so there is no pressure to simplify things by
using ARC. If this was a huge project with lots of new code to be
written, it would be a different matter, but it's really just a few
lines. So it's a nice exercise for understanding manual memory management
with Cocoa.

Of course, I might switch to ARC sooner or later but I first
like to learn and understand the old way of doing things... maybe this
also helps me to appreciate ARC more once I start using it ;)
--
Best regards,
Andreas Falkenhahn mailto:***@falkenhahn.com


_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.ne
Kyle Sluder
2016-08-29 00:10:07 UTC
Permalink
Post by Andreas Falkenhahn
Post by Alex Zavatone
Buuut, to the mind of the person learning this or trying to fit all
the complexity of learning this in their head, it might be wise in
the docs to remind the programmer that they need to do this and why
with a, "just in case you are assuming that your code is ready to
function now, please remember that the objects that end up making a
working tableView require that the tableView's dataSource object
and delegate object need to be assigned, generally to the hosting
view controller's instance of self. If this causes you to raise an
eyebrow in confusion, the reasons why you must do this are xxx and
yyyy. Likewise upon deallocation of the tableView (if it gets
called), these objects will need to be set to nil after zzzz but
before the tableView object is able to dispose of itself."
Huh? "Remember that you have to set this property to nil before you
release the object" would already be sufficient...
By the way, I still don't know whether setting the delegate to nil
before release is a general rule or does it only apply to NSTableView?
Should I also set my button delegates to nil before the buttons are
released?
Buttons don’t have delegates; they have targets.

Generally applications work fine without nilling out the targets of
their controls. This only works because controls almost exclusively
message their targets synchronously on the main in response to user
actions. There’s no opportunity for one of the target’s dependencies to
be deallocated in between the user triggering the target-action message
and the target receiving the action message.

Delegates are different because they are often messaged in response to
various exogenous events. Some of these events might happen transiently
during window teardown, which is usually a time of massive fluctuation
in an app’s object graph. This is why -windowDidClose: is a good time to
nil out delegate properties that point back and the window controller
which ultimately owns the control.

That said, it is totally possible for a control to delay-perform sending
an event, and even if it takes pains to make sure it doesn’t message the
_target_ if it’s been deallocated, one of the target’s _dependencies_
might have been deallocated. These cases are usually found after much
swearing and trial-by-fire. Such is the difference between theory and
practice.

--Kyle Sluder
Post by Andreas Falkenhahn
--
Best regards,
Andreas Falkenhahn
_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net

This email sent to ***@ml
Andreas Falkenhahn
2016-08-29 13:39:16 UTC
Permalink
Post by Kyle Sluder
Delegates are different because they are often messaged in response to
various exogenous events. Some of these events might happen transiently
during window teardown, which is usually a time of massive fluctuation
in an app’s object graph. This is why -windowDidClose: is a good time to
nil out delegate properties that point back and the window controller
which ultimately owns the control.
So does this mean that this is potentially dangerous?

[NSApp runModalForWindow:win];
[tableView setDelegate:nil];
[tableView setDataSource:nil];
[win release];

Should I move the "set to nil" calls to -windowDidClose instead?
--
Best regards,
Andreas Falkenhahn mailto:***@falkenhahn.com


_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.ne
Kyle Sluder
2016-08-29 18:07:19 UTC
Permalink
Post by Andreas Falkenhahn
Post by Kyle Sluder
Delegates are different because they are often messaged in response to
various exogenous events. Some of these events might happen transiently
during window teardown, which is usually a time of massive fluctuation
in an app’s object graph. This is why -windowDidClose: is a good time to
nil out delegate properties that point back and the window controller
which ultimately owns the control.
So does this mean that this is potentially dangerous?
[NSApp runModalForWindow:win];
[tableView setDelegate:nil];
[tableView setDataSource:nil];
[win release];
Should I move the "set to nil" calls to -windowDidClose instead?
Since you hold a strong reference to the window until after you clear out the delegate/dataSource backpointers, you know that the window cannot be reallocated until at least that point (but could be delayed to any arbitrary point in the future). So this approach is safe from window teardown causing the table view to message a zombie delegate.

--Kyle Sluder
Post by Andreas Falkenhahn
--
Best regards,
_______________________________________________

Cocoa-dev mailing list (Cocoa-***@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/gegs%40ml-in.narkive.net

This email sent to ***@ml-i

Loading...