Why does LLDB does not acknowledge complete selector name as a breakpoint? - selector

I have a function name declared as follows in OBjective C :
- (void)placeViews:(CGSize)screenSize;
In my viewDidLoad i call this function, and I want to put a breakpoint when it is called as such:
[self placeViews:size]
So in LLDB I am entering the following breakpoint command:
breakpoint set --selector placeViews:screenSize
But the LLDB is unable to resolve the breakpoint
However, when I only use "placeViews:" as the selector it finds the selector and adds the breakpoint.
What I don't get is why it finds the selector when I use "placeViews:", but it doesn't find it when i used the entire method name "placeViews:screenSize".
Why is that?
So what happens when I have multiple methods like another one such as "placeViews:screenSize:oneMoreThing" and I want to set a breakpoint only on this method, how can LLDB distinguish between "placeViews:screenSize" and "placeViews:screenSize:oneMoreThing" ?
thank you!
-Malena

placeViews:screenSize is not the selector name, the selector is just "placeViews:". The selector name does not include the variable name that is passed to the message that that selector indicates (screenSize in your case.)
That actually makes sense if you think about it, because users have to provide the "placeViews:" part of the selector when they call the method, but "screenSize" has no part of how they call it. Also, it is NOT an error to use screenSize in your #interface and a completely different name in the #implementation. So it really shouldn't be part of the name the runtime conses up for the message.
You can verify this, for instance run this in Terminal
$ otool -o | grep placeViews
name 0x100000f56 placeViews:
No mention of screenSize.

Related

Xcode LLDB throws Parse error when printing out property

I'm facing big issues when trying to print out Objective C properties in many situations when I'm almost certainly sure it SHOULD work.
Consider the following setup:
The view controller's property has strictly set class (Card *), but still, LLDB outputs an parsing error where subproperty cannot be found on object of type id.
Having an object property defined on a view controller (see points 5 & 6):
stop at breakpoint inside the controller code (f.e. in -viewDidAppear: method)
try to print out the property itself with po _card (points 1 & 2)
try to print out its subproperty with po _card.offlineURL (points 3 & 4)
an LLDB parsing error occurs
Printing out via [_card offlineURL] prints out proper object description as LLDB sends a message to Card object with no class check.
Definition of object property on the controller declares non-id class, though (point 5).
I'm expecting LLDB to print out the property object's subproperty description, NSString containing URL string in this case, but this annoying LLDB error occurs instead.
This is just a single example from many. Sometimes it affects direct property printout, numbers printing etc. These issues are way more frequent since integration of Swift began, being worse with every new version of Xcode since 6.2, including the latest 7.2.
This happens in my Objective C project in many situations, though sometimes it works fine in different cases.
Do you know about any work-arounds or fixes for this issue? I've already filed a report on Apple Bug Reporter, but this will certainly take time for Apple to even notice.
The most likely problem given the info in your question is that we don't actually have debug information for _card.
The lldb command:
(lldb) image lookup -t Card
will tell you whether lldb had debug information for Card available to it. If this doesn't find anything, then maybe some part of your project isn't getting built with debug info. If the command does find some correct definition of Card, then it must be that the debug info for the _card ivar is not getting hooked up to this type correctly.
If there is a definition of Card, then the workaround:
(lldb) po ((Card *) _card).offLineURL
is available.
For future reference, there are two other bits of behavior that are probably complicating your attempt to figure out what is going on here:
1) (w.r.t. picture 3) The Xcode IDE uses its built-in indexer for auto completion in the debug window as well as the Source Code editor. But the debugger runs off debug information, since we need to be able to debug things that aren't built in Xcode. So the fact that auto-completion can find a name in an expression doesn't tell you anything about what lldb will do.
2) (w.r.t. picture 2) po force-casts the expression you are trying to "po" to an ObjC object (i.e. "id") and then calls its description method. The description method of an ObjC object that doesn't override description prints the type name and the address. So lldb didn't need to know the type of the _card ivar to get the output you saw. We only start to need types when the expression is more complex and involves accesses to ivars or properties of an ObjC object in the expression.
Note also, by default if you do:
(lldb) print _card
lldb will evaluate the expression "_card", find it resolves to a pointer of at least type id, then follow that pointer's isa pointer into the ObjC runtime to figure out what the dynamic type is. So it is likely to print Card * in this case.
But the expression parser hasn't yet been taught to resolve the dynamic type of sub-expressions within the expression parser in mid-parse. That would actually be quite a trick... So if it doesn't know the full type of _card, then:
(lldb) print _card.offlineURL
isn't going to work, since id does indeed not have a property of that name.
You can work around this by doing:
(lldb) print _card
$0 = (Card *) 0x12345678
Then:
(lldb) print $0.offlineURL
since the result variable captures the full dynamic type information, that will also be available in subsequent expressions.

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.

Selector function with int parameter?

Using Cocos2d-iphone, and objective-c game development framework.
I create a button with:
CCMenuItemImage *slot = [CCMenuItemImage itemFromNormalImage:#"BattleMoveSelectionSlot1.png"
selectedImage:#"BattleMoveSelectionSlot2.png"
target:self selector:#selector(moveChosen:i)];
And my moveChosen method is:
-(void)moveChosen:(int)index {
}
However, for some reason I get an error on #selector(moveChosen:i) where i is an integer. How, then, may I pass an integer parameter to my function when the button is pressed?
The error is
Expected ':'
Georg is correct. Note that as implemented, this will invoke undefined behaviour since index is an int but the action method it's being used as expects an object (id) there, not an int. The signature of an action method is:
- (void)methodName:(id)sender;
Or, when used with Interface Builder:
- (IBAction)methodName:(id)sender;
(IBAction is an alias of void. The two are semantically different but functionally identical.)
Where sender is the object that sent the action message--in this case, the object you created and assigned to the slot variable.
You don't include any argument names in the selector:
#selector(moveChosen:)
Selectors don't allow for binding parameters.
Georg is partially correct. For your example, it would be:
#selector(moveChosen:)
But note: if you have more than one parameter, you do include the formal parameter names to get the selector. If your function signature were:
- (void)moveChosen:(int)index withThing:(Thing*)thing
then the selector would be:
#selector(moveChosen:withThing:)
The selector is just the name of the message that you want to send. The arguments will be provided when it is called — which means CCMenuItemImage will decide what argument is passed. If CCMenuItemImage does not support providing an integer parameter, you can't make it do that.

Is it possible to stop on a breakpoint in an instance of an object?

I've tried creating a breakpoint within a class definition, stopping on the message sent to an object instance, hoping it would then jump to the class code and allow me to walk through line by line and see the values of the local variables.
However, I'm going to venture out and say "no, this should not be possible", as there could be multiple instances of the class in memory. If someone could give a better explanation, that would be grand.
(As a side note, my alternative is excessive NSLogging of the runtime data.)
Yes, it is possible! You can add a condition to a breakpoint:
http://d.pr/yZVB+
http://d.pr/pWOB+
The program will only pause at this breakpoint when the condition is satisfied. You could choose a condition such as self == _myGlobalInstanceOfInterest.
If you don't want to store the instance in a variable, you might, for example, start the breakpoint without a condition — and then when you figure out which instance you want as the program is running, use p myObject to get the address, and then just set the condition to use the that address (such as self == 0x8badf00d).
I take it you want to break upon a message being sent to a particular instance?
Read the Xcode documentation on breakpoints and watchpoints. Basically, you can set a condition on a breakpoint so that it will automatically continue if self isn't the instance you're interested in.
Assuming you're talking about something like this:
- (void)eatAPieceOfFruit: (NSFruit *)fruit {
NSString * fruitType = [fruit species];
BOOL hasSeeds = [fruit hasSeeds];
NSInteger deliciousnessRating = [self enjoymentOfFruitType: fruitType];
NSString * reactionToEating = [self phraseForFruitType: fruitType];
// Breakpoint set here
}
The debugger has access to and knows the name of any variable that's in scope -- any variable that you would be able to use in the actual code at the line where you broke, you can also get to via the debugger. So, at the debugger prompt, type:
po reactionToEating
(that's "po" for "print object"), or the name of any other local variable to see what it is. If you want to call a method on an object that's in scope you can do so:
print (int)[reactionToEating length]
po [reactionToEating capitalizedString]

Selectors in Objective-C?

First, I'm not sure I really understand what a selector is. From my understanding, it's the name of a method, and you can assign it to a class of type 'SEL' and then run methods such as respondToSelector to see if the receiver implements that method. Can someone offer up a better explanation?
Secondly, to this point, I have the following code:
NSString *thing = #"Hello, this is Craig";
SEL sel = #selector(lowercaseString:);
NSString *lower = (([thing respondsToSelector:sel]) ? #"YES" : #"NO");
NSLog (#"Responds to lowercaseString: %#", lower);
if ([thing respondsToSelector:sel]) //(lower == #"YES")
NSLog(#"lowercaseString is: %#", [thing lowercaseString]);
However, even though thing is clearly a kind of NSString, and should respond to lowercaseString, I cannot get the 'respondsToSelector' conditional to return "YES"...
You have to be very careful about the method names. In this case, the method name is just "lowercaseString", not "lowercaseString:" (note the absence of the colon). That's why you're getting NO returned, because NSString objects respond to the lowercaseString message but not the lowercaseString: message.
How do you know when to add a colon? You add a colon to the message name if you would add a colon when calling it, which happens if it takes one argument. If it takes zero arguments (as is the case with lowercaseString), then there is no colon. If it takes more than one argument, you have to add the extra argument names along with their colons, as in compare:options:range:locale:.
You can also look at the documentation and note the presence or absence of a trailing colon.
Selectors are an efficient way to reference methods directly in compiled code - the compiler is what actually assigns the value to a SEL.
Other have already covered the second part of your q, the ':' at the end matches a different signature than what you're looking for (in this case that signature doesn't exist).
That's because you want #selector(lowercaseString), not #selector(lowercaseString:). There's a subtle difference: the second one implies a parameter (note the colon at the end), but - [NSString lowercaseString] does not take a parameter.
In this case, the name of the selector is wrong. The colon here is part of the method signature; it means that the method takes one argument. I believe that you want
SEL sel = #selector(lowercaseString);
NSString's method is lowercaseString (0 arguments), not lowercaseString: (1 argument).
Don't think of the colon as part of the function name, think of it as a separator, if you don't have anything to separate (no value to go with the function) then you don't need it.
I'm not sure why but all this OO stuff seems to be foreign to Apple developers. I would strongly suggest grabbing Visual Studio Express and playing around with that too. Not because one is better than the other, just it's a good way to look at the design issues and ways of thinking.
Like
introspection = reflection
+ before functions/properties = static
- = instance level
It's always good to look at a problem in different ways and programming is the ultimate puzzle.
From my understanding of the Apple documentation, a selector represents the name of the method that you want to call. The nice thing about selectors is you can use them in cases where the exact method to be called varies. As a simple example, you can do something like:
SEL selec;
if (a == b) {
selec = #selector(method1)
}
else
{
selec = #selector(method2)
};
[self performSelector:selec];
As per apple docs:
https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/Selector.html
A selector is the name used to select a method to execute for an object, or the unique identifier that replaces the name when the source code is compiled. A selector by itself doesn’t do anything. It simply identifies a method. The only thing that makes the selector method name different from a plain string is that the compiler makes sure that selectors are unique. What makes a selector useful is that (in conjunction with the runtime) it acts like a dynamic function pointer that, for a given name, automatically points to the implementation of a method appropriate for whichever class it’s used with. Suppose you had a selector for the method run, and classes Dog, Athlete, and ComputerSimulation (each of which implemented a method run). The selector could be used with an instance of each of the classes to invoke its run method—even though the implementation might be different for each.
Example:
(lldb) breakpoint --set selector viewDidLoad
This will set a breakpoint on all viewDidLoad implementations in your app.
So selector is kind of a global identifier for a method.