How can you inject a swift dynamic framework into an app at runtime using the LLDB debugger and iOS simulator? - swift

I would like to be able to declare global helper functions and types for use in assisting debugging and keep these in their own framework.
I have found that it is possible to load the framework using LLDB by executing the following.
#!/usr/bin/python
import lldb
def __lldb_init_module(debugger, internal_dict):
debugger.HandleCommand("command script add -f {0}.HandleCommand custom".format(__name__))
debugger.HandleCommand("command alias swift expression -l Swift -O --")
debugger.HandleCommand("command alias objc expression -l objc -O --")
def HandleCommand(debugger, command, result, internal_dict):
target = debugger.GetSelectedTarget()
process = target.GetProcess()
error = lldb.SBError()
process.LoadImage(lldb.SBFileSpec("/path/to/CustomCommandHelper.framework/CustomCommandHelper"), error)
if error.fail:
result.SetError(error)
else:
result.AppendMessage("custom command loaded")
referenced from .lldbinit
command script import /path/to/CustomCommands.py
From the debugger typing the following will now load the framework into the debugger
(lldb) custom
However I am not able to access any of the types with in it except by [ab]using objc
#objc public class TestClass2: NSObject {
public override init() {}
#objc public let text = "Test"
}
(lldb) objc id testClass2 = [[NSClassFromString(#"CustomCommandHelper.TestClass2") alloc] init]; [testClass2 text];
Test
(lldb) swift let testClass2 = CustomCommandHelper.TestClass2(); testClass2.text
error: <EXPR>:8:18: error: module 'CustomCommandHelper' has no member named 'TestClass2'
let testClass2 = CustomCommandHelper.TestClass2(); testClass2.text

Related

Call dump in lldb by object refernce

I would like to call dump method in the LLDB while using Debug View Hierarchy.
Select element (for instance View controller) -> open Object Inspector -> get the address and execute dump in lldb.
po 0x7fc1fd8301a0 works with object description as expected
e -l swift -O -- dump(0x7fc1fd8301a0) or with `` doesnt work
I have tried t o create and extension for my object:
#objc public class DumpTree: NSObject {
}
public extension DumpTree {
#objc class func apple(_ value: Any?) {
dump(value);
}
}
po [DumpTree apple:0x7fc1fd8301a0] I get the following error:
error: expression failed to parse: error: Error [IRForTarget]: Couldn't resolve the class for an Objective-C static method call
Xcode 14.0.1
Thanks
Thanks to #Jim Ingham for the comment so I have to cast the raw memory to the correct object and then it worked:
expr -l Swift -- import UIKit
expr -l Swift -- let $var = unsafeBitCast(0x7fe3f134bd70, to: UIView.self)
expr -l Swift -- dump($var)
although I had seen that answer before I didnt link between the two unfortunately

Error when creating simple dictionary with Swift

I'm learning SpriteKit, and trying to create a simple dictionary, that is, this simple dictionary:
class GameScene: SKScene {
let someDic = ["a":1, "b":2, "c":3]
print(someDic)
I constantly end up with the following error message:
Cannot find type 'someDic' in scope
What am I doing wrong?
The code you posted won't compile. The print statement has to be inside a function.
I would expect the error "Expected 'func' keyword in instance method declaration".
If you create a command line tool, this code WOULD compile and run:
import Foundation
class Foo {
let someDic = ["a":1, "b":2, "c":3]
func someFunc() {
print(someDic)
}
}
let aFoo = Foo()
aFoo.someFunc()

Why does my Swift code try and call the wrong init method?

I have the following Swift class:
public class Tree {
var obj_ : OpaquePointer
public init(fromCPtr obj:OpaquePointer) {
obj_ = obj
}
convenience init(_ levels:Int32) {
var rv : OpaquePointer?
Tree_Tree_create(levels, &rv)
self.init(fromCPtr:rv!)
}
deinit
{
Tree_Tree_dispose(obj_)
}
}
And the following test code:
import Foundation
import Tree
let t = Tree(4)
print(t.data())
I compile the Tree module with:
swiftc Tree.swift -import-objc-header Tree-Bridging-Header.h -L. -lTree_c -emit-module -emit-module-path build/Tree.swiftmodule -emit-library -module-name Tree -o build/Tree
This works without errors or warnings.
I compile my test code with:
swiftc TestTree.swift -Ibuild/
and get the following error:
TestTree.swift:4:14: error: cannot convert value of type 'Int' to expected argument type 'OpaquePointer'
let t = Tree(4)
Why is Swift selecting the pointer overload? As I understand things, Swift should not select the pointer init method unless I call init(fromCPtr some_pointer).
Using Tree(Int32(4)) in the test makes no difference.
How can I get Swift to select the correct init method?
convenience init(_ levels:Int32) {
This is not a public initializer. Add public to make it visible outside the module. The default access level is internal, which is only visible inside the module.

Issue with swift framework import

I have created a swift framework.
In this framework i have some swift file and one category in objective-C (so there is the .h and .m files).
I successfully build my framework, but when i import it into another project, only the method from my category (written in objective-C) are visible. If i try to use any swift class i got an error "Use of unresolved identifier".
I have checked the following points in my framework project :
all my swift class are public public class Toto
i have set the build settings - packaging - defines module param to yes
In my project where the framework is imported, i have the following code :
import UIKit
import myframework
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
toto()
}
func toto() {
let data = NSData()
data.isGzippedData()
var client = Client ()
NSLog("ok");
}
}
I have an error "Use of undeclared identifier" for the line var toto = Client (), but in my swift framework the class Client is public and its default constructor is public.
However, if i comment this line, the code works fine, even if the method isGzippedData is declared and implement in my framework (but in objective-C).
How can i use the swift class from my framework into my project ?

Private var is accessible from outside the class

This was done in Playground, just to simplify.
class MyPrivateVar
{
private var priv: String?
}
var myInstance = MyPrivateVar()
myInstance.priv = "Something"
No compiler warning. In fact auto-complete is showing priv without a problem.
My understanding is that outside the boundaries of {} of the class, I'm not supposed to be able to see a private anything, func nor var.
Am I missing something?
Access modifiers in Swift are implemented differently than other languages. There are three levels:
private: accessible only within that particular file
internal: accessible only within the module (project)
public: accessible from anywhere
Unless marked otherwise, everything you write is internal by default.
The Swift blog had a post about access control when the features were introduced in beta 4, and Apple's documentation has a chapter as well.
Note: this answer is for Swift 2
The Swift Programming Language states:
Swift provides three different access levels for entities within your
code. These access levels are relative to the source file in which an
entity is defined, and also relative to the module that source file
belongs to.
If you wan't to test private access level with Swift, the following step by step may help you.
1/ Create a new Xcode project.
2/ Create a file, MyPrivateVar.swift, and add the following code in it:
class MyPrivateVar {
private var priv: String? = nil
}
3/ Create a second file, MySecondClass.swift, and add the following code in it:
class MySecondClass {
init() {
var myPrivateVar = MyPrivateVar()
myPrivateVar.priv = "some string"
}
}
Xcode will immediatly give you a Swift compiler error message:
'MyPrivateVar' does not have a member named 'priv'
4/ Now, remove the two previous files from your project and create a single file TwoClassesInAFile.swift with the following code in it:
class MyPrivateVar {
private var priv : String? = nil
}
class MySecondClass {
init() {
var myPrivateVar = MyPrivateVar()
myPrivateVar.priv = "some string"
}
}
This time, you will get no Swift compiler error message and you will be able to access MyPrivateVar's priv private property from MySecondClass because priv and MySecondClass are in the same file (your TwoClassesInAFile.swift file).
Furthermore, access levels also work for global variables. For example, Xcode won't give any compiler error if the following code is part of the same ViewController.swift file:
import UIKit
private var globalPrivate : String? = nil
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
globalPrivate = "some string"
println(globalPrivate)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
However, if you define globalPrivate outside of ViewController.swift, Xcode will generate an error message:
Use of unresolved identifier 'globalPrivate'