Wrong value set when use lldb expr in Xcode8.0 and debug with iPhone6 Plus - xcode8

I use this expr to modify the speed value:
expr (void)[[[[UIApplication sharedApplication] keyWindow] layer] setSpeed:0.9f]
But the value set is -2.
Why does this happen and how do I fix it?
I try this command on another app, the result is correct....

It may be that lldb is getting the definition of these functions from the ObjC runtime type information which is incomplete. If it has the wrong signature for the function, it won't pass the arguments correctly.
What happens if you do:
(lldb) #import UIKit
then run your expression?

Related

Why can't LLDB evaluate this expression?

Neither one of these statements can be processed by LLDB... why is it unable to come up with the NSString result and print it out
expr -o -- [NSString stringWithFormat:#"%#", #"Wow this doesnt work??"]
po [NSString stringWithFormat:#"%#", #"Wow this doesnt work??"]
It seems that the expression command in lldb can generally not evaluate functions with
variable argument lists. It fails even with a simple C function:
int foo(char *msg, ...)
{
return 17;
}
(lldb) expr foo("bar")
(int) $2 = 17
(lldb) expr foo("bar", 2)
error: no matching function for call to 'foo'
note: candidate function not viable: requires 1 argument, but 2 were provided
error: 1 errors parsing expression
So this looks like a bug (or non-feature) in lldb.
This is more of academic than practical interest, but the original question and Martin's answer actually have different causes. In both cases, lldb is actually correctly refusing to call a function with more arguments than it is declared to have, but getting the actual definition wrong for different reasons.
In the first case, lldb doesn't actually have debug information for the method call [NSString stringWithFormat:format, ...]. It turns out the compiler does not emit debug information for every function your program USES, only the ones it defines. This restriction is mostly to keep the size of the debug information manageable.
So the debugger has to consult the ObjC runtime for extra type information for these kit functions. But the runtime type information doesn't encode the variable argument-ness of variable argument functions.
In the second case, what you are seeing is actually a bug in clang's debug output. It fails to emit the bit of information that tells the debugger that the function is a variable argument function.
In any case, in lldb you can work around this sort of issue by introducing declarations of commonly used functions to lldb's expression parser using the "expr-prefix" file. For instance, in Martin's case, I make a file "/tmp/expr-prefix.lldb" containing the line:
extern "C" int foo (char *msg, ...);
Then in lldb, I do:
(lldb) settings set target.expr-prefix /tmp/expr-prefix.lldb
And then you can call the function in the expression parser. A couple of caveats with this feature. This "expression prefix" file gets included in all the expression you run with the "print" command, so don't put too much stuff in there or it will slow down general expression parsing. Don't try to do things like:
#import <Cocoa/Cocoa.h>
that will be very slow and probably won't work anyway - since this depends on a whole set of #defines that the debugger doesn't know about.
But it can be very helpful if you have a few functions like this that you really need to call, but can't because we either don't know the signature or are somehow getting it wrong.
The extern "C" is required because lldb parses expressions as ObjC++.
If you want to prototype an ObjC method, you need to do it on an extension of the class you are prototyping the method for; we often have a rudimentary class def'n and the compiler doesn't like to add methods to a known class, only extensions.
I found a workaround in this article:
http://www.cimgf.com/2012/12/13/xcode-lldb-tutorial/
For example when I try to use this syntax to call method:
po [NSString stringWithFormat:#"%#", #"MyName"];
Debugger error is:
error: too many arguments to method call, expected 1, have 2
error: 1 errors parsing expression
But you can try this one:
po [[NSString alloc] initWithFormat:#"%#", #"MyName"];
Debugger message is:
$4 = 0x0a6737f0 MyName
import UIKit in debugger this worked for me
expr #import UIKit

lldb error: property not found on object of type

I am trying to debug my iOS app using lldb and I'm getting really weird errors on debug.
A few lines before my breakpoint, I've got:
CGRect frame = view.frame;
Which I can access with no problems with print frame command in lldb. However, when I try to access the frame again in lldb, I type print view.frame and get the following error:
error: property 'frame' not found on object of type 'UIView *'
This doesn't make sense as I can verify the view is a UIView* instance and has a valid property called frame by typing po view and getting correct results:
(UIView *) $4 = 0x1e199bf0 <MyAppCustomView: 0x1e199bf0; frame = (3398 3396; 204 208); layer = <CALayer: 0x1e199ce0>>
This particular lldb error happens to me a lot, and I couldn't find the cause of this error. Someone suggested at Property 'count' not found on object of type 'NSMutableArray *' PO command in lldb that one could use gdb as (gdb) p view.frame but I'm getting error: '(gdb)' is not a valid command. and I highly suspect that a gdb command would "work?" inside another debugger anyway.
Any suggestions or workarounds for this bug which occurs randomly?
Dot notation for message sending is not supported in lldb when using Objective-C. Use bracket notation and cast the result to CGRect:
p (CGRect)[view frame]
Just in case the above doesn't work (which it didn't for me, looking for the frame for a variable cell, class derived from UITableViewCell): forcing the extra parentheses seemed to help lldb's little ditty brain:
p ((CGRect)[cell frame])
presto magico:
(CGRect) $5 = origin=(x=0, y=0) size=(width=320, height=44)
I had to disable (uncheck) Thread Sanitizer in Xcode > Product > Scheme > Edit Scheme > Run > Diagnostics. With Thread Sanitizer enabled I wasn't able to access many NSView properties (e.g. bounds, frame) through LLDB.

How can I call the NSObject "class" method from gdb?

I'm using gdb 6.3.50, the one that comes with Xcode 4.4.1. It seems to get confused by my attempts to call class on an object in the debugger.
(gdb) po [JSONObject class]
A syntax error in expression, near `]'.
I assume it's getting tripped up by the word "class", which must be some kind of reserved symbol, perhaps because I'm working in Objective-C++. Certainly, I can prod it into an error with identical wording if I try to use some other C keyword:
(gdb) po [JSONObject struct]
A syntax error in expression, near `]'.
There's nothing wrong with the object itself, it seems, because gdb can call other methods on it:
(gdb) po [JSONObject objectForKey:#"UTIMESTAMP"]
<__NSCFArray 0x89c9b0>( ...(etc.>)
Is there some construct, or symbol, or something, that I can put in the command line, to force gdb to treat "class" as just a selector?
Try using the Objective-C messenger functions directly:
po (id)objc_msgSend(JSONObject, #selector(class))

What would setting a getter do?

First, some context: while answering questions on SO, I came across a post wherein the author had been trying to set a getter with syntax similar to [self.propertyGetter:newValue];. For some reason, this compiles, and I thought to myself, "this would constitute a call to nil, wouldn't it?". So, my question is, why in the heck does this 'work'? (to be perfectly clear, the poster was complaining that this had no effect, so by 'work', I mean compile).
The code you quoted is [self.propertyGetter:newValue]. Here's how the Objective-C compiler parses this.
The first thing after the left bracket has to be the receiver of the message. In that code, the receiver is the value of self.propertyGetter. The compiler transforms self.propertyGetter into [self propertyGetter]. So we can rewrite the code you quoted as [[self propertyGetter]:newValue].
Now the compiler needs to figure out the selector of the message. You usually see a keyword selector like setStatusBarHidden:animated:, which is a series of keywords followed by colons. But it turns out a keyword can be zero-length. So a colon by itself is a valid keyword selector. So the compiler sees it like this: [[self propertyGetter] :newValue]. (Using a zero-length keyword is almost always very bad style.)
You can declare an instance method using that selector. For example:
- (void):(NSObject *)newValue;
If [self propertyGetter] returns an object of a class that has that method, the code will compile and run.
If the compiler has seen any class with a method named like that, and [self propertyGetter] returns type id, then the code will compile (because id is a wildcard type and the compiler will not complain if you try to send it any known message selector). However, the app will crash at runtime if [self propertyGetter] doesn't actually understand the : message.
This compiles because all objective-C objects are dynamic entities by default. It would compile, but would crash at runtime.
Source.

'NSTableViewAnimationSlideLeft' undeclared (first use in this function)

I'm getting a compiler error: 'NSTableViewAnimationSlideLeft' undeclared (first use in this function) on this line of code:
[searchTableView removeRowsAtIndexes:[[searchTableView selectedRowIndexes] withAnimation:NSTableViewAnimationSlideLeft]];
But the most weird thing is that I couldn't find any example on internet. (just 5 results with Google). What's wrong with this method ?
thanks
[searchTableView removeRowsAtIndexes:[[searchTableView selectedRowIndexes] withAnimation:NSTableViewAnimationSlideLeft]];
Your bracket nesting is wrong:
[searchTableView removeRowsAtIndexes:
[
[searchTableView selectedRowIndexes]
withAnimation:NSTableViewAnimationSlideLeft]
];
It's syntactically legal, but I don't think you mean to send a withAnimation: message to the index set, nor to pass the return value of that message (if it had one) as the index set to removeRowsAtIndexes:.
I'm getting a compiler error: 'NSTableViewAnimationSlideLeft' undeclared (first use in this function)
It was introduced in 10.7, so make sure you're using the 10.7 SDK.
Don't forget to make this code conditional if you're supporting 10.5 or 10.6.