When printing list of references with ptr_refs, it gives somewhat vague results (at least in iOS). For example I have a sample app with this tiny ViewController class and exactly one outlet reference to a UILabel instance:
import UIKit
class ViewController: UIViewController {
#IBOutlet var label: UILabel!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print(label)
}
}
And here is the listing I get when printing references to the label:
(lldb) ptr_refs 0x102914810
0x0000000281b04630: malloc( 16) -> 0x281b04630
0x0000000283d09f18: malloc( 96) -> 0x283d09ec0 + 88
0x0000000280c18d60: malloc( 64) -> 0x280c18d40 + 32 CFXNotificationNameWildcardObjectRegistration0 bytes after CFXNotificationNameWildcardObjectRegistration
0x000000028192b408: malloc( 32) -> 0x28192b400 + 8 _UILabelStringContent._UILabelContent._defaultAttributesProvider
0x0000000283a3d2f0: malloc( 80) -> 0x283a3d2c0 + 48 CFXNotificationObjcObserverRegistration8 bytes after CFXNotificationObjcObserverRegistration
0x0000000283a3d2f8: malloc( 80) -> 0x283a3d2c0 + 56 CFXNotificationObjcObserverRegistration16 bytes after CFXNotificationObjcObserverRegistration
0x000000010290c070: malloc( 864) -> 0x10290bd20 + 848 TtC13ThreadChecker14ViewController216 bytes after TtC13ThreadChecker14ViewController
0x0000000102d058c0: malloc( 304) -> 0x102d05850 + 112
If this was not just a sample app and it had rather 10-15 outlet references, I would have a hard time trying to figure out which exact reference in my code this line is at - 0x000000010290c070: malloc( 864) -> 0x10290bd20 + 848 TtC13ThreadChecker14ViewController216 bytes after TtC13ThreadChecker14ViewControllerThe.
I also tried the -s option with MallocStackLogging enabled, but when it comes to outlet references, this information is not very helpful.
Provided I have only the address of an object and the listing given by ptr_refs, is there a way to find out which exact variable/field in my code corresponds to the reference in the listing?
Firstly, the names on the right give us some clues, from which you could guess that TtC13ThreadChecker14ViewController is associated with your ViewController class.
_Tt is for target; C is for class; 13 is the length of the "ThreadChecker" string, and your project name is ThreadChecker; 14 is the length of the "ViewController" string, and that is the class. Your ViewController starts at 0x10290bd20.
Secondly, the malloc is at 0x000000010290c070. Notice that 0x000000010290c070 - 0x10290bd20 = 0x350 which is 848 in decimal, so that's why it puts the offset as 848 from the start of "ViewController", i.e., 0x10290bd20 + 848. So this offset, 848, is an important piece of the puzzle.
Thirdly, the next thing to do is figure out what line in the source code is at offset 848. For this, we begin by doing
(lldb) image list
[ 0] 4EB96CD6-42E0-34D8-AB5B-2418F5C55678 0x000000010252c000 /Users/daniel.wong/Library/Developer/Xcode/DerivedData/testLLDB-eqmuowhdphumqdhcyvcydgrybiue/Build/Products/Debug-iphonesimulator/testLLDB.app/testLLDB
Even in this simple example, there might be 200-300 libraries loaded with the app. For the present investigation of your own source code, you can ignore the libraries, only look at the [ 0] (first element in the list).
(in my example, the app is called testLLDB; in yours, you might see ThreadChecker instead of testLLDB).
An important point to note is that image list gives the so-called file address where the addresses you got from Xcode that you used for ptr_refs might be quite different (actual addresses in the simulator or iPhone memory during an actual run when it gets loaded into a part of the RAM), e.g., 0x102914810 in your example. The file address refers to a virtual address as defined by each object file. For the purpose of finding the source code line number with the offset 848, you can work with these file addresses and you now just need one more piece of information, i.e., where is the start of the code for ViewController, so you can take offset 848 from there.
Fourthly, to find the start of the code for ViewController, you can use
(lldb) image dump sections /Users/daniel.wong/Library/Developer/Xcode/DerivedData/testLLDB-eqmuowhdphumqdhcyvcydgrybiue/Build/Products/Debug-iphonesimulator/testLLDB.app/testLLDB
where we specified only the image of the testLLDB app that we got as the first element of the image list, and not the 100s of libraries after that.
lldb will then give you something like:
Sections for '/Users/daniel.wong/Library/Developer/Xcode/DerivedData/testLLDB-eqmuowhdphumqdhcyvcydgrybiue/Build/Products/Debug-iphonesimulator/testLLDB.app/testLLDB' (x86_64):
SectID Type Load Address Perm File Off. File Size Flags Section Name
---------- ---------------- --------------------------------------- ---- ---------- ---------- ---------- ----------------------------
0x00000100 container [0x0000000000000000-0x0000000100000000)* --- 0x00000000 0x00000000 0x00000000 testLLDB.__PAGEZERO
0x00000200 container [0x000000010252c000-0x0000000102532000) r-x 0x00000000 0x00006000 0x00000000 testLLDB.__TEXT
0x00000001 code [0x000000010252d260-0x000000010252fa80) r-x 0x00001260 0x00002820 0x80000400 testLLDB.__TEXT.__text
0x00000002 code [0x000000010252fa80-0x000000010252fb5e) r-x 0x00003a80 0x000000de 0x80000408 testLLDB.__TEXT.__stubs
0x00000003 code [0x000000010252fb60-0x000000010252fce2) r-x 0x00003b60 0x00000182 0x80000400 testLLDB.__TEXT.__stub_helper
0x00000004 data-cstr [0x000000010252fce2-0x00000001025309bf) r-x 0x00003ce2 0x00000cdd 0x00000002 testLLDB.__TEXT.__objc_methname
0x00000005 data-cstr [0x00000001025309c0-0x0000000102531817) r-x 0x000049c0 0x00000e57 0x00000002 testLLDB.__TEXT.__cstring
0x00000006 regular [0x0000000102531820-0x0000000102531b50) r-x 0x00005820 0x00000330 0x00000000 testLLDB.__TEXT.__const
...
There's more, but for this simple ViewController, these first few sections are enough for our purpose. Look at the first code section, where its range is [0x000000010252d260-0x000000010252fa80). So it is starting from 0x000000010252d260. Here is where we add the offset 848. But we add in hex, so we add 0x350 to 0x000000010252d260 to get 0x000000010252d5b0.
Fifthly and finally, we can see which part of our source code was referencing the label, by:
(lldb) image lookup -a 0x000000010252d5b0 --verbose
Address: testLLDB[0x00000001000015b0] (testLLDB.__TEXT.__text + 848)
Summary: testLLDB`key path getter for testLLDB.ViewController.label : Swift.Optional<__C.UILabel> : testLLDB.ViewController + 80 at <compiler-generated>
Module: file = "/Users/daniel.wong/Library/Developer/Xcode/DerivedData/testLLDB-eqmuowhdphumqdhcyvcydgrybiue/Build/Products/Debug-iphonesimulator/testLLDB.app/testLLDB", arch = "x86_64"
CompileUnit: id = {0x00000000}, file = "/Users/daniel.wong/OneDrive - V-Key Pte Ltd/ios/testLLDB/testLLDB/testLLDB/ViewController.swift", language = "swift"
Function: id = {0x10000032e}, name = "key path getter for testLLDB.ViewController.label : Swift.Optional<__C.UILabel> : testLLDB.ViewController", mangled = "$s8testLLDB14ViewControllerC5labelSo7UILabelCSgvpACTK", range = [0x000000010252d560-0x000000010252d5bf)
FuncType: id = {0x10000032e}, byte-size = 8, compiler_type = "() -> ()
"
Blocks: id = {0x10000032e}, range = [0x10252d560-0x10252d5bf)
LineEntry: [0x000000010252d560-0x000000010252d5c0): /Users/daniel.wong/OneDrive - V-Key Pte Ltd/ios/testLLDB/testLLDB/<compiler-generated>
Symbol: id = {0x000000a4}, range = [0x000000010252d560-0x000000010252d5c0), name="key path getter for testLLDB.ViewController.label : Swift.Optional<__C.UILabel> : testLLDB.ViewController", mangled="$s8testLLDB14ViewControllerC5labelSo7UILabelCSgvpACTK"
Variable: id = {0x100000345}, name = "label", type = "testLLDB.ViewController", location = DW_OP_fbreg(-16), decl = ViewController.swift:18
So we see it is "key path getter for testLLDB.ViewController.label : Swift.Optional<__C.UILabel> : testLLDB.ViewController" at ViewController.swift:18, which is what you were looking for. (ok, for my test view controller, the label is in line 18, as I also had a viewDidLoad that took a few lines; for yours, you should get the appropriate line number for your ViewController).
This post is already too long, but just to add one more little piece of info: those references to your label from CFXNotificationObjcObserverRegistration, that is part of CoreFoundation, so we see that not at references are from our own source code. Many references would often be from system frameworks like CoreFoundation, etc.; if you put your view with the label in a storyboard and add auto layout constraints, for example, the ptr_refs command will additionally give you a number of other references that are related to auto layout, e.g.,
NSContentSizeLayoutConstraint.NSLayoutConstraint._container
0x000060000049ce48: malloc( 96) -> 0x60000049ce40 + 8 NSContentSizeLayoutConstraint.NSLayoutConstraint._container
0x00006000035db208: malloc( 64) -> 0x6000035db200 + 8 NSLayoutDimension.NSLayoutAnchor._referenceItem
0x00006000035db3c8: malloc( 64) -> 0x6000035db3c0 + 8 NSLayoutDimension.NSLayoutAnchor._referenceItem
0x00006000035e9560: malloc( 64) -> 0x6000035e9540 + 32
Related
I am creating an app where I need to modify specific bytes in a Data object, but it crashes when I modify too many bytes at one time.
I thought the problem might be because my app was hanging for too long, but I put my code in a DispatchGroup and it didn’t help.
//amount and interval are Ints
var pos: Int = 1
let count = data.count
var tempData: Data = data
while (pos < count) {
tempData[pos - 1] = tempData[pos - 1] + UInt8(amount)
pos += interval
}
This code crashes my app when I provide it with a large Data object, but works fine with small ones.
I found my problem. Since I was adding two UInt8s together, there was a chance that the resulting UInt8 would be invalid (greater than 255), which resulted in a crash. I fixed this by changing my + to &+ so the UInt8 overflows back to 1.
Stack of Plates: Imagine a (literal) stack of plates. If the stack gets too high, it might topple.
Therefore, in real life, we would likely start a new stack when the previous stack exceeds some threshold. Implement a data structure SetOfStacks that mimics this. SetOfStacks should be composed of several stacks and should create a new stack once the previous one exceeds capacity.
SetOfStacks. push () and SetOfStacks. pop() should behave identically to a single stack (that is, pop ( ) should return the same values as it would if there were just a single stack).
FOLLOW UP
Implement a function popAt (int index) which performs a pop operation on a specific substack.
The book solution for pop at index:
public int popAt(int index) {
21 return leftShift (index, true);
22 }
23
24 public int leftShift(int index, boolean removeTop) {
25 Stack stack = stacks.get(index);
26 int removed_item;
27 if (removeTop) removed_item = stack.pop();
28 else removed_item = stack.removeBottom( );
29 if (stack.isEmpty(» {
30 stacks.remove(index);
31 } else if (stacks.size() > index + 1) {
32 int v = leftShift(index + 1, false);
33 stack . push(v);
34 }
35 return removed_item;
36 }
the explanation of line 32 i nt v = leftShift(index + 1, false); is missing. Can anyone please help me with that?
Well, the leftShift function's objective is to pop from the stack given in the "index" input. After this, it does the adjustment between the other stacks.
So, in line 27 pops the element from the specified stack.
After this, in line 32, it calls itself recursively, giving this time as a first argument the index of the next stack, and as a second false. The first argument indicates that in the next recursive call, it will use the next stack. The second argument, being set as false, means that the required action (pop) has been done, and now only the adjustment is left.
The function when the flag removeTop is set as false does the adjustment as I referred above. The difference, in this case, is that instead of the top element it removes the bottom one from each of the following stacks. This way the needed adjustment is done.
With the term adjustment, I mean the elements that need to be moved from the next stacks to the previous ones each time so as to fill any empty spaces.
I hope it helps.
Say there are two variables:
let number1 : UInt8 = 100;
let number2 : UInt8 = 100;
You add and print them
print(number1 + number2) //This prints 200
Now define one more
let number3 : UInt8 = 200;
And try to add now
print(number1 + number3) // Throws execution was interrupted
I understand that the sum of number1 and number3 would be out of range of UInt8 but explicit casting also does not help, for example following line also gives the same error:
print(UInt8(number1 + number3)) // Throws execution was interrupted
The way I found was to do the following:
print(Int(number1) + Int(number3))
Is there a better way of adding UInt8 number when their sum goes out of range?
Girish K Gupta,
UInt8 has max range 0 to 255. Which you can check using UInt8.min and UInt8.max. Basically 0 to 2 power 8.
Issue with print(number1 + number3) will return 300. 300 is greater then 255 hence crash.
When you add two UInt8 result will be by default casted to UInt8 hence the crash
Finally when you Int(number1) + Int(number3) you are forcefully casting number1 and number3 to Int.
When you use Int, range of its value depends on the platform on which you are running it either 32 bit or 64 bit. for example its range can be -2,147,483,648 to 2,147,483,647 for 32 bit.
When you add Int to Int result will be typecasted to Int. And believe me 300 is way inside the range :)
As per your question is there a better way to do it :)
Apple's docs clearly specifies and instructs to use Int rather then UInt8 or UInt32 or even UInt64 until and unless using UInt8, UInt32 or UInt64 is absolutely essential.
Here is the quote from apple's doc :)
“Use UInt only when you specifically need an unsigned integer type
with the same size as the platform’s native word size. If this is not
the case, Int is preferred, even when the values to be stored are
known to be non-negative. A consistent use of Int for integer values
aids code interoperability, avoids the need to convert between
different number types, and matches integer type inference,”
Excerpt From: Apple Inc. “The Swift Programming Language (Swift 2.2).”
iBooks. https://itun.es/in/jEUH0.l
So best thing for you to do :) follow apples instruction :) Change the number1,number2 and number3 to Int :) Problem solved :)
Hence no crash :)
As you've said casting both UInt8 variables to Int overrides the default exception on overflow as the resulting Int now has room to fit the sum.
To avoid casting the variables for every operation we would like to overload the operator like this:
func + (left: UInt8, right: UInt8) -> Int {
return Int(left) + Int(right)
}
However this will give us a compiler error as the + operator is already defined for adding two UInt8's.
What we could do instead is to define a custom operator, say ^+ to mean addition of two UInt8's but add them as Int's like so:
infix operator ^+ { associativity left precedence 140 }
func ^+ (left: UInt8, right: UInt8) -> Int {
return Int(left) + Int(right)
}
Then we can use it in our algorithms:
print(number1 ^+ number3) // Prints 300
If you however want the result to just overflow you can use the overflow operators from the standard library:
print(number1 &+ number3) // Prints 44
So I'm writing a lowpass accelerometer function to moderate the jitters of the accelerometer. I have a CGFloat array to represent the data and i want to damp it with this function:
// Damps the gittery motion with a lowpass filter.
func lowPass(vector:[CGFloat]) -> [CGFloat]
{
let blend:CGFloat = 0.2
// Smoothens out the data input.
vector[0] = vector[0] * blend + lastVector[0] * (1 - blend)
vector[1] = vector[1] * blend + lastVector[1] * (1 - blend)
vector[2] = vector[2] * blend + lastVector[2] * (1 - blend)
// Sets the last vector to be the current one.
lastVector = vector
// Returns the lowpass vector.
return vector
}
In this case, lastVector is defined as follows up at the top of my program:
var lastVector:[CGFloat] = [0.0, 0.0, 0.0]
The three lines in the form vector[a] = ... give me the errors. Any ideas as to why i am getting this error?
That code seems to compile if you pass the array with the inout modifier:
func lowPass(inout vector:[CGFloat]) -> [CGFloat] {
...
}
I'm not sure whether that's a bug or not. Instinctively, if I pass an array to a function I expect to be able to modify it. If I pass with the inout modifier, I'd expect to be able to make the original variable to point to a new array - similar to what the & modifier does in C and C++.
Maybe the reason behind is that in Swift there are mutable and immutable arrays (and dictionaries). Without the inout it's considered immutable, hence the reason why it cannot be modified.
Addendum 1 - It's not a bug
#newacct says that's the intended behavior. After some research I agree with him. But even if not a bug I originally considered it wrong (read up to the end for conclusions).
If I have a class like this:
class WithProp {
var x : Int = 1
func SetX(newVal : Int) {
self.x = newVal
}
}
I can pass an instance of that class to a function, and the function can modify its internal state
var a = WithProp()
func Do1(p : WithProp) {
p.x = 5 // This works
p.SetX(10) // This works too
}
without having to pass the instance as inout.
I can use inout instead to make the a variable to point to another instance:
func Do2(inout p : WithProp) {
p = WithProp()
}
Do2(&a)
With that code, from within Do2 I make the p parameter (i.e. the a variable) point to a newly created instance of WithProp.
The same cannot be done with an array (and I presume a dictionary as well). To change its internal state (modify, add or remove an element) the inout modifier must be used. That was counterintuitive.
But everything gets clarified after reading this excerpt from the swift book:
Swift’s String, Array, and Dictionary types are implemented as structures. This means that strings, arrays, and dictionaries are copied when they are assigned to a new constant or variable, or when they are passed to a function or method.
So when passed to a func, it's not the original array, but a copy of it - Hence any change made to it (even if possible) wouldn't be done on the original array.
So, in the end, my original answer above is correct and the experienced behavior is not a bug
Many thanks to #newacct :)
Since Xcode 6 beta 3, modifying the contents of an Array is a mutating operation. You cannot modify a constant (i.e. let) Array; you can only modify a non-constant (i.e. var) Array.
Parameters to a function are constants by default. Therefore, you cannot modify the contents of vector since it is a constant. Like other parameters, there are two ways to be able to change a parameter:
Declare it var, in which case you can assign to it, but it is still passed by value, so any changes to the parameter has no effect on the calling scope.
Declare it inout, in which case the parameter is passed by reference, and any changes to the parameter is just like you made the changes on the variable in the calling scope.
You can see in the Swift standard library that all the functions that take an Array and mutate it, like sort(), take the Array as inout.
P.S. this is just like how arrays work in PHP by the way
Edit: The following worked for Xcode Beta 2. Apparently, the syntax and behavior of arrays has changed in Beta 3. You can no longer modify the contents of an array with subscripts if it is immutable (a parameter not declared inout or var):
Not valid with the most recent changes to the language
The only way I could get it to work in the play ground was change how you are declaring the arrays. I suggest trying this (works in playground):
import Cocoa
let lastVector: CGFloat[] = [0.0,0.0,0.0]
func lowPass(vector:CGFloat[]) -> CGFloat[] {
let blend: CGFloat = 0.2
vector[0] = vector[0] * blend + lastVector[0] * ( 1 - blend)
vector[1] = vector[1] * blend + lastVector[1] * ( 1 - blend)
vector[2] = vector[2] * blend + lastVector[2] * ( 1 - blend)
return vector
}
var test = lowPass([1.0,2.0,3.0]);
Mainly as a followup for future reference, #newacct's answer is the correct one. Since the original post showed a function that returns an array, the correct answer to this question is to tag the parameter with var:
func lowPass(var vector:[CGFloat]) -> [CGFloat] {
let blend:CGFloat = 0.2
// Smoothens out the data input.
vector[0] = vector[0] * blend + lastVector[0] * (1 - blend)
vector[1] = vector[1] * blend + lastVector[1] * (1 - blend)
vector[2] = vector[2] * blend + lastVector[2] * (1 - blend)
// Sets the last vector to be the current one.
lastVector = vector
// Returns the lowpass vector.
return vector
}
I'm trying to understand this code:
315 let existingIndex = this._editors.indexOf(editableNode.editor);
316 if (existingIndex == -1) {
317 let x = this._editors.length;
318 this._editors[x] = editableNode.editor;
319 this._stateListeners[x] = this._createStateListener();
320 this._editors[x].addEditActionListener(this);
321 this._editors[x].addDocumentStateListener(this._stateListeners[x]);
322 }
http://mxr.mozilla.org/mozilla-release/source/toolkit/modules/Finder.jsm#320
Especially addEditActionListener(this); what is this? MDN docs say it should be nsIEditActionListener but I can't find what this listener is comprised of MDN docs takes to broken page.
nsIEditor - MDN
this is the Finder object; it implements the nsIEditActionListener interface (http://mxr.mozilla.org/mozilla-release/source/toolkit/modules/Finder.jsm#395)
That interface is defined here: http://mxr.mozilla.org/mozilla-release/source/editor/idl/nsIEditActionListener.idl
So the code essentially attaches the Finder object to the editor, presumably so it can be notified of changes made in the editor at a later point.