How to print out a property's contents using Xcode debugger? - ios

I'm writing an iOS app and I need help using the built-in Xcode debugger. Suppose I have an object called HomeViewController that has three properties
#property (nonatomic) BOOL finished;
#property (nonatomic, strong) NSArray *myArray;
#property (nonatomic, strong) NSString *myName;
#synthesize finished = _finished, myArray = _myArray, myName = _myName;
Suppose I have a breakpoint in this class. How would I view the contents of these properties? I've tried things such as po myName, print myName and print [self myName] but I can't figure out how to do this. I've tried using LLDB but I keep getting the same error that this person encountered (lldb fails to print variable values with "error: reference to 'id' is ambiguous") . The accepted answer to this question was, LLDB is broken and that I should just use GDB; however, I refuse to accept that something so fundamental is broken.
Nevertheless, I've also tried using GDB with similar commands as above; however, I can't get GDB to work either. Help please

Once you place a breakpoint, run, and the program stops at the breakpoint, hover your cursor over the variable/value you want to see like this:
You could also place an NSLog(#"%#", yourLabel.text); to view the contents of that label/other object type.
One other option is to run GDB in the console like this:
gdb
attach <your process name>
And then use the po (print-object) command to view the value of a variable like this:
po variableName
To view the value of primitive types (int, float, long, double, char, etc.), you can just use the print command while running GDB in the console like this:
print yourPrimitiveVariable
Hope this helps!
EDIT:
With the po command, you can print out the value of an object using both the property name (self.myProperty) or the ivar name (possibly _myProperty). I demonstrate this here:

Try with following expression in debug area to print object,
p self.view.bounds.size.width
or use,
po self.view
p - Print is only uses to print normal/simple values
while,
po - Print Object works same as NSLog to print value of an object

Related

How to create a new object and assign properties in Objective-C?

I'm trying to bridge an Objective C SDK with React Native and I'm having some trouble. I have a Subclass of NSObject and I'm trying to set some property values but I can't get it to work.
I have tried to change the property in the header, and in the imp file with out any difference.
PrinterSDK.h (which has libPrinterSDK.a)
#interface Printer : NSObject
#property (nonatomic, readonly) NSString* name;
#property (nonatomic, readonly) NSString* UUIDString;
#end
RNPosPrint.m
#interface Printer ()
#property (readwrite) NSString* name;
#property (readwrite) NSString* UUIDString;
#end
RCT_EXPORT_METHOD(printTestPaper:(NSString*)name:(NSString*)uuid)
{
Printer* printer = [[Printer alloc] init];
printer.name = name;
}
But I keep facing issue with the setter for some reason I can't figure out.
ExceptionsManager.js:94 Exception '-[Printer setPrinterName:]: unrecognized selector sent to instance 0x13fd25b90' was thrown while invoking printTestPaper on target RNPosPrint with params (
"Test Printer",
"XXX-XXX-XXX"
)
You do not report the names of your .h and .m files or what else is in the .m – e.g. #implementation of Printer? The class printTestPaper belongs to? Without details like this it is difficult for anyone to help you, you need to help people help you.
That said some points that may help you:
The #interface Printer () where you open up the properties to be writeable should be in the your Printer.m file – in general do not try to open up access to a type's properties from outside the type's implementation, it is both bad design and may not work as you hope (as you just found out).
The code to support a #property is generated by the compiler when it compiles the #implementation, #interface's themselves produce no executable code – they describe the accessible parts of the #implementation.
setter=<name> provides a different name for the auto-created property setter function. While a method <name> will be created to set the property using dot syntax the properties name is still used, e.g. in your case printer.name = ... is still used even with the setter=setPrinterName:. You can call the auto-created method using standard method syntax, that failed in your case for the reasons above.
Using setter=<name> or getter=<name> are really advanced features and you probably will never need to use them – when you do need to use them you will know! Just avoid them till then.
If you wish to provide a method which creates the object and sets properties then do this in the type's implementation. The usual way of doing this is to provide an init method that does this, e.g. in this case it might be - initWithName:(NSString *)printerName { ... }, or an equivalent class method which does the allocation and sets the parameters, e.g. in this case it might be + newWithName:(NSString *)printerName { ... }.
HTH
Since it's an interface from statically linked library it is simply not possible to extend or manipulate. Not without tempering with the compiler.

Cannot resolve enum values by name in Xcode debugger

With an enum typedef'd in a global header file used throughout my project, I am unable to refer to the individual enum values by name while using lldb in Xcode.
For example, if I am stopped at a breakpoint anywhere the enum type is available, and I try to evaluate something at the lldb prompt in Xcode (e.g. (lldb) p (int)EnumConstant), lldb complains:
error: use of undeclared identifier 'EnumConstant'
Furthermore, if I try to set a conditional breakpoint using an enum constant in the condition (e.g. right-click breakpoint in Xcode > Edit Breakpoint... > Condition: EnumConstant == someLocalVar), then Xcode complains every time it tries to evaluate that condition at that breakpoint:
Stopped due to an error evaluating condition of breakpoint 1.1: "EnumConstant == someLocalVar"
Couldn't parse conditional expression:
error: use of undeclared identifier 'EnumConstant'
Xcode's code completion popover even resolves a suggestion for the enum constant when I begin typing the name in the "Edit Breakpoint..." window, so Xcode itself doesn't have a problem resolving it.
Is there an option I can set in lldb or Xcode so that lldb maintains the enum identifiers after compilation? I'm assuming the enum constants get translated to their ordinal value during compilation, causing the executable to discard the identifiers, but thats just my naive speculation.
When I use the equivalent code in a simple GNU C program in Linux or Cygwin (minus the class definitions obviously), but using gcc/gdb instead of Xcode/lldb, I don't have these problems. It is able to resolve the enum values no problem.
I've created a tiny Xcode iPhone project to demonstrate what I mean. Using any of the enum_t constants below within the ViewController.m context (the for-loop is a good place to demo) will produce the same results.
ViewController.h:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
typedef enum
{
eZero, eOne, eTwo, eCOUNT
}
enum_t;
extern NSString const * const ENUM_STR[];
#end
ViewController.m:
#import "ViewController.h"
#implementation ViewController
NSString const * const ENUM_STR[eCOUNT] = { #"eZero", #"eOne", #"eTwo" };
- (void)viewDidLoad
{
[super viewDidLoad];
for (enum_t value = eZero; value < eCOUNT; ++value)
{
NSLog(#"%-8# = %d", ENUM_STR[value], value);
}
}
#end
This is a bug (fairly longstanding) in how the name->Debug Information lookup-accelerator tables for enums are built. While enum types are listed, enum values are not. That was surely done to save output debug info size - debug information gets quite big pretty quickly, and so there's a constant tension between the cost of adding more info and the utility of that more info. So far this one hasn't risen to the level of inclusion.
Anyway, doing a search through "all debug information for anything with a name that matches 'eZero'" is prohibitively slow even for decent sized projects, and gets really bad for large ones. So lldb always uses these name->Debug Info tables for its first level access.
Because the accelerator tables do contain the enum type by name (and more important for you typedefs by name as well), the workaround is to do:
(lldb) expr enum_t::eZero
(int) $0 = 0
Of course, if you have truly anonymous enums, then you are pretty much out of luck till this info gets added to the accelerator tables.
BTW, the Xcode symbol completion in the Debugger Console window is done using the Xcode SourceKit indexer, not lldb. So the completions offered from Xcode are not a reflection of lldb's knowledge of the program.
BBTW, gdb doesn't use compiler-made accelerator tables (these were an Apple extension up till the new DWARF 5 standard) but manually builds an index by scanning the debug info. That allows them to index whatever seems best to the debugger. OTOH, it makes debugger startup quite a bit slower for big projects.

"Use of undeclared identifier"

I'm pretty new to Objective C. Keep getting this error
"Use of undeclared identifier"
for this line of code:
NSString *textOut1 = textOut.text;
Obviously I am just trying to pull the textbox text. I have declared the following in my h file
#property (weak, nonatomic) IBOutlet UITextField *textOut;
So I cannot understand why I keep getting that damn error. Thanks!
Use this:
NSString *textOut1 = _textOut.text;
Checkout the extra underscore I added in front of textOut
Read the paragraph titled Most Properties Are Backed by Instance Variables in this apple documentation page.
To access the property textOut of an object referred to by the variable someVariable, you write someVariable.textOut. So to access the property textOut of the object that is self, you write self.textOut. You omitted the owner — self in this case.
self.textOut.text is what you need.
A property is basically something like a class variable in Java that requires a public getter and setter to work with. So you cannot use it in a .m file directly, but need to utilize the getter and setter. Objective C on iOS actually provides you with these methods by itself. Hence, when you create a property, under the hood, you have code that does a getter and setter by itself.
You can set the value as :
_textOut = BLAHBLAH
And get it as :
[self textOut.text]
or
self.textOut.text
or even _textOut.text (this is technically the local variable that is referenced by textOut)
Or in your case,
`NSString *textOut1 = [self textOut.text];`
or NSString *textOut1 = self.textOut.text;
or NSString *textOut1 = _textOut.text; // This is probably the least recommended one.
Though I believe the Stanford class says it is always better to do [self textOut].
If you are not (#synthesize) synthezising the property yourself then it will be synthesized with the instance variable having a Underscore at the start of the name.
try :
NSString *textOut1 = _textOut.text;

iOS / xcode - NSNumber literal updates being ignored by Xcode

1) I declare a NSNumber property is a view controller header file #property NSNumber *myNumber;
2) I set that property to a NSNumber literal and log the output:
self.myNumber = #9;
NSLog(#"myNumber is: %#", self.myNumber);
3) The above works as expected. Then I change the #9 to #10. and run the program. It does not work, the property is still set to a value of 9.
4) I make a small change to the NSLog text (a space, a full stop, anything) then rerun the program. It now does work! (updating to the new value, e.g. #10)
Any thoughts on why this is happening would be MUCH appreciated, thanks
Sometimes, Xcode gets stuck on little things like this. When something weird like this happens, the first thing to try is a clean - CmdshiftK.

Assign Enum to Variable in Objective-C

How can I assign an enum to a variable and access its value later? I thought this would be pretty simple, but every time I try to assign the enum value to a variable (no type mismatches or warnings in Xcode appear) my app crashes with an EXC_BAD_ACCESS error.
Here's how I setup my enum in my header file (BarTypes.h):
typedef enum {
BarStyleGlossy,
BarStyleMatte,
BarStyleFlat
} BarDisplayStyle;
No issues there (reading and using the values at least). However, when I create a variable that can store one of the enum values (BarStyleGlossy, BarStyleMatte, or BarStyleFlat) then try to set that variable, the app crashes. Here's how I setup and use the variable:
//Header
#property (nonatomic, assign, readwrite) BarDisplayStyle barViewDisplayStyle; //I've also tried just using (nonatomic) and I've also tried (nonatomic, assign)
//Implementation
#synthesize barViewDisplayStyle;
- (void)setupBarStyle:(BarDisplayStyle)displayStyle {
//This is where it crashes:
self.barViewDisplayStyle = displayStyle;
}
Why is it crashing here? How do I store the value of an enum in a variable? I think the issue has to do with a lack of understanding about enums on my end, however if I follow conventional variable setup and allocation, etc. this should work. Any ideas on what I'm doing wrong?
Please note that I'm new to enums, so my vocabulary here may be a bit mixed up (forgive me - and feel free to make an edit if you know what I'm trying to say).
I found a few references about enums across the web:
What is a typedef enum in Objective-C?
Using enum types as properties in Objective C
How to create global enum
How do I define and use an ENUM in Objective-C?
I also tried searching Apple's Developer site but only came up with results about types for Apple APIs (ex. Foundation, UIKit, etc.)
EDIT: Here's how I call the setupBarStyle method:
BarView *bar = [[BarView alloc] init];
[bar setupBarStyle:displayStyle];
Just in case anyone out there is still trying to figure out how to assign an enum value to an enum typed variable or property...
Here is an example using a property.
In the header file...
#interface elmTaskMeasurement : NSObject
typedef NS_ENUM(NSInteger, MeasurementType) {
D,
N,
T,
Y,
M
};
#property(nonatomic) MeasurementType MeasureType;
#end
In the file where the object is created...
elmTaskMeasurement *taskMeasurement = [[elmTaskMeasurement alloc] init];
taskMeasurement.MeasureType = (MeasurementType)N;
The method you implement is called setupBarStyle:, but you call setupBarShape: on the object.
I had this error myself but the error was caused by a different bug I off course create myself.
The setter of my property "myApplicationState" was as follows:
-(void)setApplicationStyle:(myApplicationStyle)applicationStyle{
self.applicationStyle = applicationStyle;
//some more code
}
Off course this would result in an endless loop because in the setter, the setting is called again, and again, and again.
It had to be:
-(void)setApplicationStyle:(myApplicationStyle)applicationStyle{
_applicationStyle = applicationStyle;
//some more code
}

Resources