Variable is not a static member of class - objective-c

I'm working on a GameKitHelper class, and it's mostly written in C++, but with Objective-C in some places as well, inside an .mm file.
I removed a bit of functionality to isolate the error:
void GameKitHelper::PopulateFriendScores(DynArray<GameCenterScore> *FriendScores)
{
GKLeaderboard *leaderboardRequest = [[GKLeaderboard alloc] init];
if (leaderboardRequest != nil)
{
leaderboardRequest.playerScope = GKLeaderboardPlayerScopeFriendsOnly;
leaderboardRequest.timeScope = GKLeaderboardTimeScopeAllTime;
leaderboardRequest.range = NSMakeRange(1,25);
[leaderboardRequest loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error)
{
int i = 0;
printf("%d", i);
}];
}
}
The error I get here is:
'int GameKitHelper::i' is not a static member of 'class GameKitHelper'

This is a gcc bug. See Objective-C++ block vs Objective-C block for one of many reports of it.
<soapbox>I recommend avoiding Objective-C++ as much as possible. It's slow to compile, bloated to run (particularly with ARC since it turns on -fobjc-arc-exceptions), buggy in the compiler and the debugger, and mostly a mess in my experience giving the worst of both worlds. C++ is fine. Objective-C is fine. Just keep the interface between them as small as possible. </soapbox>
But switching to clang 2.0 might fix this specific problem.

In case it might help someone else...
I am required by the needs of my project to use the 10.6 SDK and LLVM-gcc 4.2. I cannot require clang for the code to compile.
I worked around this problem by declaring my variable as a shared_ptr in the parent function... putting the actual object I need on the heap. In the block, I access the object through the shared_ptr variable. This arrangement causes the shared_ptr to be implicitly copied into the block while the copy in the parent function is free to be released. Since I am not declaring a variable in the block, I bypass the bug.
I used a preprocessor check to use a normal stack variable if the code is building on clang or some other compiler.

Related

OBJC_PRINT_VTABLE_IMAGES and OBJC_PRINT_VTABLE_SETUP does not show any output

I've tried to use OBJC_PRINT_VTABLE_IMAGES and OBJC_PRINT_VTABLE_SETUP environmental variables on Objective-C executable in order to learn about vtable mechanism in Objective-C objects. Unfortunately the mentioned environment variables have no effect on console output, despite the fact that runtime acknowledged that the variables were set:
ยป OBJC_PRINT_OPTIONS=1 OBJC_PRINT_VTABLE_IMAGES=YES /Applications/TextEdit.app/Contents/MacOS/TextEdit
objc[41098]: OBJC_PRINT_OPTIONS is set
objc[41098]: OBJC_PRINT_VTABLE_IMAGES is set
I've tried to use both variables on executables provided by system (TextEdit) and my own. With no effect.
Whole vtable mechanism in Objective-C objects is obscure. It's hard to find information about this mechanism on Apple pages. There is some info from other sources, but no official documentation:
http://www.sealiesoftware.com/blog/archive/2011/06/17/objc_explain_objc_msgSend_vtable.html
http://cocoasamurai.blogspot.com/2010/01/understanding-objective-c-runtime.html
Why these variables are not working? Does vtables in current version of Objective-C are deprecated?
In this case, the answer is pretty straightforward - vtable dispatch is no longer optimized in the objective-c runtime, and was probably a bad idea in the first place.
vtable-based dispatch was one of the first attempts to speed up frequent calls in the objective-c runtime, but note that it predates the current method caching solution. The problem with using a fixed set of selectors as in the vtable solution not only means increased memory for every class in the runtime, but it also means that if you're using an architecture which doesn't result in isEqualToString: being called frequently, for example, you now have a completely wasted pointer for EVERY class in the runtime that overrides ONE of those selectors. Whoops.
Also, note that Vtable dispatch by design couldn't work on 32-bit architectures, which meant that once the iOS SDK was released, and 32bit was again a reasonable target for objective-c, that optimization simply couldn't work.
The relevant documentation that I can find for this is in objc-abi.h:
#if TARGET_OS_OSX && defined(__x86_64__)
// objc_msgSend_fixup() is used for vtable-dispatchable call sites.
OBJC_EXPORT void objc_msgSend_fixup(void)
__OSX_DEPRECATED(10.5, 10.8, "fixup dispatch is no longer optimized")
__IOS_UNAVAILABLE __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE;
Nowadays, there aren't many vestigial fragments of vtable dispatch left in the runtime. A quick grep over the codebase shows a few places in objc-runtime-new.mm:
#if SUPPORT_FIXUP
// Fix up old objc_msgSend_fixup call sites
for (EACH_HEADER) {
message_ref_t *refs = _getObjc2MessageRefs(hi, &count);
if (count == 0) continue;
if (PrintVtables) {
_objc_inform("VTABLES: repairing %zu unsupported vtable dispatch "
"call sites in %s", count, hi->fname());
}
for (i = 0; i < count; i++) {
fixupMessageRef(refs+i);
}
}
ts.log("IMAGE TIMES: fix up objc_msgSend_fixup");
#endif
And
*********************************************************************
* fixupMessageRef
* Repairs an old vtable dispatch call site.
* vtable dispatch itself is not supported.
**********************************************************************/
static void
fixupMessageRef(message_ref_t *msg)
Which pretty clearly indicates that it's not supported.
See also, the method stub for it (if you were to do it without a compiler generated call-site), found in objc-msg-x86_64.s:
ENTRY _objc_msgSend_fixup
int3
END_ENTRY _objc_msgSend_fixup
Where int3 is the SIGTRAP instruction, which would cause a crash if a debugger isn't attached (usually).
So, while vtable dispatch is an interesting note in the history of objective-c, it should be looked back as little more than an experiment when we weren't quite familiar with the best ways to optimize common method calls.

Can you send a message that an object won't catch?

I'm reading this book and it says that this code will compile but cause a runtime exception. But when I run it on my computer it doesn't compile: "No known instance method..."
#import "Fraction.h"
int main (int argc, char * argv[])
{
#autoreleasepool {
Fraction *f = [[Fraction alloc] init];
[f noSuchMethod];
}
return 0;
}
My question is when does doing this cause a runtime exception and when does it cause a compile-time warning?
The compile-time error is because the selector noSuchMethod does not appear on any class the compiler has seen. Under ARC, the compiler cannot safely decide how to apply memory management rules in that case (it could try to follow standard naming conventions, but that could lead to extremely difficult bugs if the selector were declared with alternate semantics in some other header). It is also almost certain a mistake, so the compiler rightfully balks at guessing. (There is another issue related to the return type, and before ARC the compiler would guess about that, but it generally wasn't what you wanted even if it happen to guess right most of the time.)
If -noSuchMethod were known to exist on some class, but not Fraction, then the compiler would issue a warning. At runtime, if f failed to respond, you'd get a runtime exception. (This was the old behavior; it seems that clang may have gotten a bit more strict in my experiments and will throw an error now in this case, too. This may be the confusion with your book if it was written before the change, or the author has not rechecked it in a while.)
If noSuchMethod were known to exist, but f were declared of type id, then no warning would be generated. At runtime, if f failed to respond, you'd get a runtime exception.
It depends ...
When you use ARC then, per default, the compiler will throw an error for a method call when the method name is not known at compile time.
When you don't ARC then you get a warning only at compile time.
You can, however, customize the warning/error level of the compiler to get is passed in both cases.
Objective-C binds method calls during runtime. If you manage to get it compiled then you could even react on the runtime error right before the exception is thrown and dynamcially register a method during runtime under the name of noSuchMethod and actually perform some code when ever the method is invoked in the future during the same runtime session. It is probably this behaviour of dynamic binding during runtime that the autor of your book is trying to explain by example.

Objective-C ARC and longjmp

What is the best practice for mixing Objective-C ARC with longjmp?
I am using Lua as scripting language, and my platform exports custom library for scripts. Entry points do check arguments with luaL_checkinteger(L, 2) (among others), which, in turn, may call luaL_typerror(L, 2, ...), that is implemented in Lua with setjmp/longjmp. As far as I know, ARC simply auto-generates retain/release code, but what happens if it longjmps out of scope? Will this code leak on mistyped arguments?
static int
set_tag(lua_State *L)
{
NSControl *control = (__bridge NSControl *)lua_topointer(L, 1);
[control setTag:(NSInteger)luaL_checkinteger(L, 2)]; // may longjmp!
return 0;
}
In the snippet above, control will be temporarily retained by ARC, but with longjmps uncatchable nature, corresponding release call may never happen. On the other hand, all arguments may be checked before assigning to control variable.
static int
set_tag(lua_State *L)
{
NSInteger tag = luaL_checkinteger(L, 2); // may longjmp!
NSControl *control = (__bridge NSControl *)lua_topointer(L, 1);
[control setTag:tag];
return 0;
}
Does it resolve [potential] leak above? Are there better ways to do this?
UPDATE: longjmp only unwinds to Lua internals, and never crosses any system code, except for Lua source (which is aware), and my entry points (which I hope are aware).
I'm pretty sure that second snippet does right, but I need kind of formal proof.
LATE UPDATE:
LuaJIT implements dwarf2-compatible errors, so they are just like C++ exceptions. Pass -fobjc-arc-exceptions compiler flag to arc-enabled sources with Lua code and any retained object will be released on any lua_error. Nothing to worry about now! You are still not allowed to throw errors across Cocoa runtime, though.
I recall that original Lua may be compiled with exceptions too, but I'm not sure.
Doesn't really matter if ARC is in use or not; any setjmp/longjmp that jumps over any frame of code from the system frameworks will yield undefined behavior (for the same reason that exceptions cannot be used for recoverable error handling).
So, yes, that code might leak. Might because it depends on whether the compiler emits a retain/release in that block and where. Might also because whether the compiler emits retain/release will be impacted by the optimization level and, over time, the version of the compiler.
longjmp only unwinds to Lua internals, and never crosses any system
code, except for Lua source (which is aware), and my entry points
(which I hope are aware).
That is helpful. As long as you structure your entry points such that they never intermingle system scope with Lua jumpable scopes, you should be OK. I would recommend turning off ARC in the source files where you have to manage this (and, of course, put the ObjC->Lua interface into a nicely encapsulated bit of implementation so the rest of your code can be ARC clean).
Consider, though, that there is non-obvious risk:
for(id x in anArray) {
... lua call that causes longjmp ...
}
The above would cause lua to "jump over" system code. Same goes for enumerateWithBlock:, KVO, Notification handlers, etc...
You're going to have to think very very carefully about every potential stack trigger by a call from Lua into your code. If that call triggers any kind of automated behavior on the part of the system that could then call Lua API that could trigger a longjmp, all bets are off.
longjmp() may cause crashes or leaks in ARC. Arranging the code so longjmp() and ARC don't interfere is difficult.
If the longjmp() is only for a fatal error path and you expect to halt the process in response then you may be able to ignore the problem. This is what ARC does with C++/ObjC exceptions by default. ARC code is expected to leak when exceptions are thrown. There's a compiler option to enable the clean up code for exceptions, but that hurts performance.
If the longjmp() is not a process-killing error then your best option is to turn off ARC in any code that may be skipped by a longjmp() call.

Objective-C: Instance variable used while 'self' not set... but it is

I've been tasked with cleaning up some Clang errors in a code base. I am very new to iPhone development and Objective C, but have found most of the problems trivial... this one is stumping me though, when I'm sure its something embarrassing.
From a ZAttributedString class:
- (id)initWithAttributedString:(ZAttributedString *)attr {
NSParameterAssert(attr != nil);
if ((self = [super init])) {
_buffer = [attr->_buffer mutableCopy];
_attributes = [[NSMutableArray alloc] initWithArray:attr->_attributes copyItems:YES];
}
return self;
}
The clang warning is "Instance variable used while 'self' is not set to the result of '[super or self] init...]', with the dereferencing of attr's _buffer attribute being highlighted.
If it helps, the warning also seems to mention that the problem is found when calling from this method:
- (id)copyWithZone(NSZone *)zone {
return [(ZAttributedString *)[ZAttributedString allocWithZone:zone] initWithAttributedString:self];
}
Can anyone please explain to me what exactly the defect is here?
TIA!
Do not use -> to access instance variables, especially when the ivar is from some other object.
Do this:
_buffer = [[attr string] mutableCopy];
Same goes for that nasty attr->_attributes. Apparently, ZAttributedStringexposesattributes` as a property in the private header.
That compiler warning does seem, at the very most optimistic, entirely misleading and, likely, quite wrong in description. Filing a bug to have that clarified would be useful.
Note that #maddy's claim that using -> to access the instance variables directly in the attr string passed as it acts like a copy constructor is incorrect.
The incoming attr may be a ZAttributedString instance or an instance of a subclass or, really, an instance of any class that implements the same interface as ZAttributedString. Thus, you really must go through the accessors to guarantee that you are grabbing the correct state.
Now, as an implementation detail, ZAttributedString could require that the inbound instance be a non-subclassed instance of ZAttributedString, but it should use isMemberOfClass: to assert that requirement (and, please, don't do that).
The only spot where direct ivar access is sometimes used to pull state from another object is in the implementation of copyWithZone:, but that is exceedingly fragile and oft leads to whacky broken behavior. In fact, copyWithZone: (outside of the various plist compatible value classes) has been rife with fragility and the source of many many many bugs.
It seems like you are seeing the exact same bug as this: "[Bug 15092] New: static analyzer false positive: reports instance variable used while 'self' is not set to the result of [(super or self)] init". It has a very similar code attached to reproduce the bug.
If you run that code in Xcode 4.6.3 you can verify that it gives the same false warning as you are seeing.
The bug was resolved with the comment:
This is fixed in trunk, or at least mostly fixed -- there are still a few edge
cases where the warning will fire, but not your project.
(Dave, for now all of the main analyzer engineers do work at Apple, so there's
no real need to file duplicates. The LLVM people who don't work at Apple don't
have access to Apple Clang, which ships with Xcode, and this fix didn't make
Xcode 4.6. You can also get newer checker builds from
http://clang-analyzer.llvm.org)
As you can see the bug is fixed but still present in Xcode 4.6. Hold out for the next version of Xcode and the analyzer warning should be gone.

Proxies and ARC, incompatible?

I'm trying to implement proxies for database stored procedures. The idea is to have my code find a series of stored procedures in the database, then create a proxy object in memory which will implement methods matching those stored procedures. That proxy object could be derived from NSProxy or NSObject, both should work. The basic idea is that any method calls made to my proxy object would go to resolveInstanceMethod: and be handled there if the method call matched a stored procedure in the database.
But before even getting close to my objective, I'm stumped by ARC seemingly not allowing me to do method calls to undeclared methods. Back in the days before ARC, we got a warning like "object may not respond to selector" from the compiler and that was that, but with ARC enabled, I'm getting a compiler error saying "no known instance method for selector...". This also happens if I first cast the proxy object to (id).
This all seems to imply that ARC is incompatible with runtime discovery of methods, which is one of the fundamental characteristics of objective-c. It seems to mandate that all methods used must be declared in interfaces before compilation, just as in C++.
Or, more likely, I'm missing something essential. If so, what?
Edited to include code:
int main(int argc, const char * argv[])
{
#autoreleasepool {
// insert code here...
NSLog(#"Hello, World!");
MyTargetClass *mtc = [[MyTargetClass alloc] init];
[mtc doSomething];
}
return 0;
}
MyTargetClass contains nothing:
#interface MyTargetClass : NSObject
#end
The [mtc doSomething] call elicits a warning if in a non-ARC project, but elicits a compiler error with ARC. IMHO that means I can't add methods to a class in runtime if ARC is used.
mwehlou,
First, if you don't show us any code, then it is really hard to help you.
Second, if you know that you will provide the instance method, then you can silence the warnings with the following #pragmas:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[Your Selector Based Code Here]
#pragma clang diagnostic pop
If that is the warning symbol, well, you can probably find it from within your build settings in Xcode.
Andrew