[Interest] [OS X] How to enable ARC for *.mm files (which qmake var)?

Till Oliver Knoll till.oliver.knoll at gmail.com
Sun Jan 19 22:28:57 CET 2014


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Am 17.01.14 21:58, schrieb Thiago Macieira:
> ... If you want to do any advanced thing with qmake, you need to
> read those two dirs and see what they do. There's a lot of
> undocumented code.
> 
> Which can break in the next version, because it's undocumented.

At least for QMAKE_OBJECTIVE_CFLAGS I would give my vote to add it to
the "official qmake API" by documenting it. If Qt Creator would
highlight it as keyword that would also add to the experience that one
is using an "official feature".

Especially since mixing Objective-C++ with Qt is already part of the
official qmake API (with OBJECTIVE_SOURCES) and QMAKE_OBJECTIVE_CFLAGS
seems to be the only way to add compiler flags for those *.mm sources.


By the way, as indicated in my previous post, enabling Automatic
Reference Counting (ARC) does indeed work. One might stumble across
the following, just as I did: if your previous non-ARC enabled OS X
platform-specific code looks like the following:

  NSView *view = reinterpret_cast<NSView *>(m_qwidget->winId());

According to the Qt docs of QWidget:

"On Mac OS X, the type returned depends on which framework Qt was
linked against. If Qt is using Carbon, the {WId} is actually an
HIViewRef. If Qt is using Cocoa, {WId} is a pointer to an NSView."

So in case Qt links against Cocoa - Carbon is not supported at all
anymore since Qt 5 - then the returned value is indeed a pointer to an
NSView, so the cast here is perfectly fine.

However with ARC enabled you will get the following error:

"cast of 'WId' (aka 'unsigned long long') to 'NSView *' is disallowed
with ARC"

This is because an Objective-C object "crosses from a non-ObjectiveC
world (C++/Qt) into an ObjectiveC world, and the compiler now needs to
know how to deal with that object. [1]

That's where "bridged casts come into play [2]. As Qt does not create
the NSView for us (but merely passes along a pointer to it, which
should be valid for at least until our method ends, unless the actual
QWidget is deleted), we to not want to change ownership by using
__bridge cast. But how do we tell the ObjectiveC compiler? Because a

  NSView *view = reinterpret_cast<__bridge NSView
*>(m_windowMarker->winId());

or even a good old C-style cast

  NSView *view = (__bridge NSView *)(m_windowMarker->winId());

will lead to another error like:

  "incompatible types casting 'WId' (aka 'unsigned long long') to
'NSView *' with a __bridge cast"


So the following casting voodoo will solve the issue:

  NSView *view = (__bridge NSView *)reinterpret_cast<void
*>(m_windowMarker->winId());

The trick seems to be to cast the 'unsigned long long' first to a
pointer to void, and only then apply the bridge cast to pointer to
NSView. [3]

Oh yes, the beauty of casting everything to 'void *' convinces even
the strictest compiler that we know what we are doing ;)



Cheers, Oliver



[1] For the interested: a good starting point is probably here:

https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html


[2] See "Managing Toll-Free Bridging" in

https://developer.apple.com/library/mac/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011226

[3] Courtesy "Fancy cast for ARC" in

http://stackoverflow.com/questions/19779783/ios-qt-load-qwidget-inside-uiview
-----BEGIN PGP SIGNATURE-----
Version: GnuPG/MacGPG2 v2.0.22 (Darwin)
Comment: GPGTools - http://gpgtools.org
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iEYEARECAAYFAlLcQ5kACgkQHVnxr7UPh0OgYwCgm56z3UfDs+2ZYdvV1B7x2rRO
eawAoKNa4tyG6qY1mtbzn/+8QYYHRMcc
=Anqc
-----END PGP SIGNATURE-----



More information about the Interest mailing list