Viewing Swift optional values in debugger - debugging

Trying to get my feet wet in writing and debugging Swift code, I wrote the following. This is on OS X 10.10.2, Xcode 6.2.
let text : String? = "This is some text.\nJust for fun."
let lines : [String]? =
text?.componentsSeparatedByCharactersInSet(
NSCharacterSet.newlineCharacterSet())
println("\(lines)")
Breaking on the println ... line, the debugger's variable view shows Some as the value of lines. In my understanding, this indicates that lines is of an optional type and contains a value wrapped in Some, as opposed to being None.
Knowing that, how can I use the debugger to inspect what that value actually is? I tried:
clicking the small "i" button, which produces the output "Some" in the debugger console.
entering po lines and po lines! in the debugger console, which yields EXC_BAD_ACCESS. Update: Following a fresh installation of Xcode, po lines seems to have no effect, i.e. no output.
The final line prints Optional(["This is some text.", "Just for fun."]), which is exactly what I'd like the debugger to show.
How can I get at the unwrapped string array value of lines, and what is the difference between the optional variable lines, whose unwrapped value the debugger doesn't show, and the optional variable text, whose value it does show? Will I actually have to introduce an auxiliary variable every time I want to debug an optional value, or use printf-debugging?

Maybe I am misunderstanding, but you made "lines" an optional value. Because of that, you would need to unwrap it in your println statement or not make it an optional value. Take off the "?" after your "lines" declaration first and see if that works for you.
let lines : [String] =

To print an optional value use:
if let unwrappedLines = lines { // only executes if lines is not nil
println("\(unwrappedLines)") // prints the unwrapped variable
}

Related

Xcode Breakpoint and LLDB - How do I open a file (e.g. in Preview) from a given fileURL stored in a variable?

I have a variable in Swift code that runs in iOS simulator and contains an existing fileURL. I want to have the file opened in macOS (not the iOS Simulator) when I hit a breakpoint.
I added an action "Shell Command" to the breakpoint to open the file. The file exists because if I copy-paste the file's path to Terminal, it opens in Preview.
However, the Xcode console says the contrary:
The file /"/Users/tomkraina/Library/Developer/CoreSimulator/Devices/FBA16E00-9450-40E8-9650-1489A67E344C/data/Containers/Data/Application/BB97DB72-FF2A-4087-BD42-2934C63D3323/tmp/7E2303B8-0629-475A-862A-2550351FB448/OutlineExport.pdf" does not exist.
First Question: How do I tell Xcode to open a file with provided fileURL in a variable on breakpoint?
Next thing I tried was to open the file using LLDB, but I cannot find out how to evaluate a command parameter in LLDB, because backticks is only for scalars:
(lldb) shell open `temporaryFile.fileURL.path`
The file /105553157711856 does not exist.
Second Question: How to I evaluate argument parameter to get a string in LLDB?
I don't have a good answer for the first question. It would be interesting to check whether the path that is in the Xcode error message is correct - maybe it's getting it from the value incorrectly. If you copy the path from the error message, go to Terminal and try to open it, does that work? Anyway, this sounds to me like a bug in Xcode. It got some kind of path out of your variable and tried to open it, which should have worked. If you want to follow up, it's probably best to file a bug report with the Apple Feedback.
For the second question, you have to know a little about how variables work in lldb. Some variables have obvious values, for instance, in C a pointer has the pointer value, an integer the integer value, etc. Other variables (any kind of Struct being the obvious example) are actually containers of other values and don't really have a "value" themselves.
lldb can show you what a swift string really is using the --raw option:
(lldb) v --raw str1
(Swift.String) str1 = {
_guts = {
_object = {
_countAndFlagsBits = {
_value = -3458764513820540912
}
_object = 0x8000000100003f50 (0x0000000100003f50) strings`symbol stub for: Swift.print(_: Any..., separator: Swift.String, terminator: Swift.String) -> () + 4
}
}
}
That's probably really interesting to people working on the Swift Standard Library and has the virtue of being the truth. But for most purposes, it's not a terribly useful representation.
lldb handles that problem by adding a notion of "Summary Formatters" that generate a string representation for objects based on their type. There's one for "Swift.string" that digs around in the object, finds where the actual string is, and returns that text. If you don't pass --raw and there's a summary formatter, then lldb will show you the summary:
(lldb) v str1
(String) str1 = "some string here"
That is also the value that you want to try and open.
The backtick syntax in lldb gets the value of the entity, not its summary, which is why that didn't work for a swift string. However, you can fetch and act on the summaries for local variables using lldb's Python interpreter and the SB API. So for instance:
(lldb) script
Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.
>>> var = lldb.frame.FindVariable("str1")
>>> var.GetSummary()
'"some string here"'
So then if that was a file path you wanted to open, you can use Python to do that, like:
>>> os.system("open {0}".format(var.GetSummary()))
The file /private/tmp/some string here does not exist.
256
except of course your var has to hold the path to a real file...
If you want to learn more about the lldb Python API's the API docs are here:
https://lldb.llvm.org/python_api.html
and a general tutorial for using Python in lldb is here:
https://lldb.llvm.org/use/python-reference.html
And more information on variable formatting is here:
https://lldb.llvm.org/use/variable.html

Xcode XCUITest - extra characters entered into searchField when using typeText

I have a test in Xcode (XCUITests) that uses typeText to enter a string into a searchField. For our test, we do 2 taps into the searchField first. Then, we do:
searchField.typeText(ourStringHere + "\n")
When this line runs, it types the first character 2 extra times. So, if we pass in "tree", it will type "tttree". This obviously causes our tests to fail.
On this screen in our app that we are testing, we have actions occur based on matching as you type. So, after the first character is typed, some results are shown. I believe this is causing a timeout issue.
Then Xcode is trying to type the whole word again. I believe this also happens twice. On the third attempt, the screen has settled down with it's background actions and the word it then successfully typed.
Ifs there was some way to override typeText() to delete anything it had previously tried, that would be helpful. Also, adding some pauses in between characters as they are typed would help. We could then have the test wait for the background actions to show all of the results and then type the next letter.
Other than this, I don't know how to fix this.
Based on your preconditions I think you should paste text instead of typing (but it is a little unsafe if you run your tests in parallel)
let pasteMenuItem = app.menuItems.firstMatch
UIPasteboard.general.string = "Preparing Pasteboard"
searchField.tap()
searchField.tap()
_ = pasteMenuItem.waitForExistence(timeout: 5)
UIPasteboard.general.string = ourStringHere + "\n"
pasteMenuItem.tap()
Also, check out comments here typeText() is typing inconsistent characters for a slow typing.

Xcode > Symbolic Breakpoint > Log Message > prints class of object property instead of value

I have created a symbolic breakpoint in Xcode 11.3.1 to log the name property of the first parameter ($rdx) to an Objective-C method. Although my expression:
(NSString*)[(NSRelationshipDescription*)$rdx name]
prints the expected value when passed via the print object (po) command, the message logged by the breakpoint prints instead
class name = _PFEncodedString
It also logs the value as expected if I enter a Debugger Command (with po) instead of Log Message as the breakpoint Action. But of course that omits my label (unless I were to try to print a formatted string – what a kludge!), and it prints an extra blank line. I was hoping Log Message would be helpful in debugging a difficult problem.
Am I doing something wrong or is Xcode's Log Message just broken?
Well, since no one has answered after a week, I conclude that this is a bug in Xcode. I have submitted it to Apple in FB7585394.

Is it possible to reference value of another watched expression in vs2010?

When I hit a breakpoint I have "this" in my watch window
this -> 0x2cceb42c
I copy that value into a new line in my watch window (it displays both the name and the value in hex)
0x2cceb42c -> 0x2cceb42c
On a third line I cast my value into a pointer to my class:
(MyClass*)0x2cceb42c -> { members of class... }
The problem is, next time I run the program the address has changed so I have to edit the address on my third line. Only, I'm not just using it in the third line, but also in 5 other watch expressions. Which means the next time I run the program I have to change the address in all 5 watched expressions.
What I would like to do is have my 5 watch expressions refer to the value in line 2 - then I only ever need to change the address in one place and all my watches will update automatically.
Is this possible? Or can anyone suggest a trick to achieve as close to this as possible?
Clarification: I want to see the results of my 5 watch expressions when I'm on a breakpoint elsewhere in the code (where "this" is no longer the value I'm interested in, which is why I'm copying the address out of "this").

Xcode 3.2 Debug: Seeing whats in an array?

Whilst debugging in Xcode_3.1.2 I am pretty sure I could see the contents of my NSString arrays. However after upgrading to 3.2 I only see the following ...
I know I can print the object in (gdb) using "po planetArray" or simply click in the debugger and "print description to console" I am just curious, as I am sure it worked prior to upgrading. Anyone know anything about this?
cheers gary
edit: data formatters is on and it shows what you see above ...
This is because GDB acts as if the variable you are viewing is out of scope while it really just is confused about what each part function or method call of the data formatter is returning (the data formatter is the "{(unichar *)Xcode_CFStringSummary($VAR, $ID)}:s" part you are seeing.
When you are debugging and you are in a method where you know a local variable must be in scope right now, open the debugger window and the area where you can see "Variable", "Value" and "Summary" column titles double click the "Summary" row entry for the variable you are interested in and enter the following (for array types like NSArray or NSCFArray):
"{(int)[$VAR count]} objects {(NSString *)[(NSArray *)$VAR description]}:s"
then press return. You have now overwritten the default data formatter provided by Xcode's GDB extension (to be found in various plists at "/Developer/Library/Xcode/CustomDataViews/") with your own data formatter string.
Your own overrides are saved at "~/Library/Application Support/Developer/Shared/Xcode/CustomDataViews/CustomDataViews.plist" and if you want to have the Apple default data formatter back just double click the row for a variable of the same type and delete whatever is there.
The nitty-gritty details: In the custom expression above the "{}" construct tells GDB to execute a command (as if you where executing it from GDB's debugger command line, which means the same restrictions apply: you need to specify the return type in cast parens in front of every function or method which returns something). The ":s" behind the closing curly brace tells Xcode and GDB to reference the "Summary" column. Also valid would be ":v" which references the "Value" column which most of the time is just the pointer value. Everything that is outside of the curly braces is shown verbatim.
Unfortuntely curly braces can't be nested which invalidates ternary operator conditionals.
So with the above data formatter you should see the following for an empty NSArray:
"0 objects (\n)"
If you want to write your own data formatters as GDB extensions (equivalent to specifying a function akin to Xcode_CFStringSummary above) you can do so. Take a look at the following header: "/Developer/Applications/Xcode.app/Contents/PlugIns/GDBMIDebugging.xcplugin/Contents/Headers/DataFormatterPlugin.h"
it will tell you all you need to know. But it can be hard to get it right. It might be easier and less error prone to just define another method on your class and call that from the data formatter string instead of "description".
In the Run > Variables View menu in Xcode, is "Use Data Formatters" enabled?
I am not sure if this helps but if you select the array value to wish to see in the debugger window and the go to the Menu : Run > Variables View > View Variable As
you can change it from "NSCFString *" to "NSString *". You then see the value so "Planet_1" for example.
Cheers,
Kevin

Resources