Open 05262b81-54a9-4fe1-bf6a-96f8042de10e opened 8 years ago
Upon revisiting this, I just realized where the _OBJC_CLASS_$_iTunesApplication
references came from. unsafeDowncast
only skips the checked cast under optimization. In debug mode, it emits the check, which causes the symbol. So this problem can be worked around by using unsafeBitCast
instead of unsafeDowncast
. But that's still awkward, and it's also still trivial to create other references to the _OBJC_CLASS_$_iTunesApplication
symbol. For example, just passing the object to print()
is sufficient to cause the error (presumably passing it to any generic function is problematic).
Attachment: Download
Environment
Xcode 7.3 beta 3 (7D141l) Apple Swift version 2.2 (swiftlang-703.0.6.5 clang-703.0.21) Target: x86_64-apple-macosx10.9Additional Detail from JIRA
| | | |------------------|-----------------| |Votes | 3 | |Component/s | Compiler | |Labels | Bug | |Assignee | None | |Priority | Medium | md5: f286d808225a261022b3da23f5218625Issue Description:
The way ScriptingBridge works is classes are created dynamically at runtime based on an application's scripting dictionary. In order to actually work with these classes, you use the
sdp
command-line tool to emit an Obj-C header from an app's scripting dictionary (which can be extracted with thesdef
tool). This Obj-C header declares all the classes, but of course there are no@implementation
blocks because the classes are created dynamically at runtime.This works perfectly fine in Obj-C. Using these classes from Obj-C doesn't ever actually reference the metadata symbols, e.g.
_OBJC_CLASS_$_iTunesApplication
, because you never message a class directly or access any ivars. Instead you call something like+[SBApplication applicationWithBundleIdentifier:]
and cast it to the expected dynamic type.Unfortunately, in Swift, attempting to use this always emits references to symbols like
_OBJC_CLASS_$_iTunesApplication
, which fails at link-time. I'm not actually sure why it even does this. Given a project that generates the appropriate headers withsdp
for iTunes, the following line is sufficient to reproduce the issue:Note the use of
unsafeDowncast
to eliminate the type-check. I don't know why Swift is emitting a reference to_OBJC_CLASS_$_iTunesApplication
here, but it is, and so this fails at link-time.I'm not entirely sure what the right solution here is. One possible solution is to add a Clang attribute that marks an
@interface
block to say that the class will exist at runtime and therefore no references to symbols like_OBJC_CLASS_$_iTunesApplication
should be emitted, and then to teach swiftc to respect this (e.g. to make it dynamically look up the class at runtime instead of using the symbol). But beyond needing to change Clang, this also means needing to changesdp
to emit the appropriate attribute.Another solution might be to simply figure out why swiftc is emitting a reference to
_OBJC_CLASS_$_iTunesApplication
at all, and change swiftc to avoid emitting references to symbols like that for Obj-C classes imported via the bridging header unless there's no choice. But I assume that swiftc is emitting that reference for some reason, even though I don't know what it is, and presumably getting rid of this reference would have negative repercussions elsewhere. In addition, this also relies on everyone remembering to useunsafeDowncast()
everywhere that involves a cast to one of these ScriptingBridge-generated classes.A third option might involve teaching swiftc to treat subclasses of
SBObject
specially, though I don't know if that's sufficient (e.g. I don't know if references to protocols also involve any kind of symbol reference that would also cause a link error).I've attached a sample project that demonstrates this issue.