Hello all,
I’ve discovered a bug that’s causing crashes when Swift code interoperates with
AppKit in a certain way. I intend to file a bug report, but I’m not sure
whether the bug should be filed as a Swift bug, or as an AppKit bug since a
case could probably be made for either, and I thought I would ask the list
first.
What’s happening, basically, is that when an NSTextFieldCell subclass contains
Objective-C-compatible reference-type properties, and is loaded from a .nib
file in which its containing text field has its Baseline aligned to some other
object via autolayout, its properties get over-released when the cell is
deallocated. A simple example that will cause the crash is:
@objc(Foo) class Foo: NSObject {}
@objc(CustomTextFieldCell) class CustomTextFieldCell: NSTextFieldCell {
let foo = Foo()
}
The equivalent code in Objective-C works properly and does not crash:
#import <Cocoa/Cocoa.h>
@interface Foo: NSObject
@end
@implementation Foo
@end
@interface CustomTextFieldCell: NSTextFieldCell
@property (nonatomic, strong) Foo *foo;
@end
@implementation CustomTextFieldCell
- (instancetype)initWithCoder:(NSCoder *)coder {
self->_foo = [Foo new];
return [super initWithCoder:coder];
}
@end
The problem seems to occur, as far as I can tell, because when the Baseline
layout relation is applied, AppKit copies the text field’s cell. Subsequently,
NSCell’s -copyWithZone: method calls NSCopyObject, which in turn calls a
private function named “fixUpCopiedIvars.” With an Objective-C cell class,
fixUpCopiedIvars calls class_getIvarLayout, and retains all its instance
variables, so both the original cell and the copy have an owning reference to
all of them. This retain is then balanced by a release when the cell is
deallocated. With a Swift cell class, however, class_getIvarLayout returns
NULL, so the ivars are never retained; however, this nonexistent retain is
still balanced by a release when the cell is deallocated. The result is that
the program accesses freed memory, leading to a crash or worse.
A sample project demonstrating all this is here:
http://www.charlessoft.com/bug_examples/Crash_Swiftly.zip
So, there’s clearly a bug here, but I’m not sure which of these three
possibilities is correct:
- This is a bug in AppKit, because NSCell should not be using the deprecated
NSCopyObject or assuming that class_getIvarLayout will work.
- This is a bug in the Swift<->Objective-C bridge, because Swift can be used to
write Objective-C objects, and legacy Objective-C code like NSCopyObject that
interacts with said objects may assume that it can access instance variables
via class_getIvarLayout; thus, the latter should work.
- Or option 3: The Swift team considers it to be a bug in AppKit, and the
AppKit team considers this to be a bug in Swift, or maybe the Foundation team
gets involved to make this into a triangle. This is obviously the worst-case
scenario. ;-)
What does the community think? Should I file this as a bug on Swift?
Foundation? AppKit? All three?
Thanks,
Charles
_______________________________________________
swift-users mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-users