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

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.

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

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

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

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()

Class Declaration and Usage

Newbie question. I am simply trying to declare a class (or even struct) as a separate Swift file and then build it or use it inside a separate class. Consider this:
import Foundation
class PayloadTest{
var label: String
init(label:String) {
self.label = label
}
}
---- then separate file
import WatchKit
import Foundation
class InterfaceController2: WKInterfaceController {
var payloadtest = PayloadTest(label: "test string init")
payloadtest.label = "test" // this line gives error - says it was expecting a declaration
.
.
.
}
I can't figure out why if I make a class or struct at the same level in my watchOS extension, it is not allowed to be accessed or recognized when I try to access the variables.
As dfd mentioned in the comment section this is a scope issue. In many programming languages you just can't write statements (expressions) which is not either a declaration or initialization or a method call outside the function or a method.
Let me explain what I said,
In a class or a structure definition any statements(expressions) apart from declaration & initialization should be present in the function (method) definition.
class PayloadTest{
//The below statement is declaration, which declares label is an property of type string.
var label: String
init(label:String) {
//The below statement is an assignment, and it compiles and execute fine as this is inside a init method.
self.label = label
}
}
However in your second snippet,
import WatchKit
import Foundation
class InterfaceController2: WKInterfaceController {
//The below statement compiles fine even tough it isn't present inside a method coz it is initialization statement.
var payloadtest = PayloadTest(label: "test string init")
//However the compiler complains about the below assignment statement because, this is neither an declaration nor an initialization statement and it should not be outside method.
//So you've to keep this statement inside a method for compiler to stop complaining.
payloadtest.label = "test" // this line gives error - says it was expecting a declaration
....
}
To make the second snippet work put the below line of code in a method and call that method,
payloadtest.label = "test"
So always remember any statements apart from declaration, initialization should be present inside a method or function definition and this applies to most of the languages.
Please go through the various scope levels present. HTH :)
You can't have an expression nested in a class like that. You can get around this by putting your code in a closure which you immediately call:
class InterfaceController2: WKInterfaceController {
var payloadtest = {
let pt = PayloadTest(label: "test string init")
pt.label = "test"
return pt
}()
you can try to move that code in a function. (Swift 3.0 version)
class InterfaceController: WKInterfaceController {
var payloadtest = PayloadTest(label: "test string init")
fileprivate func test() {
payloadtest.label = "test" // tape this line in a function
}
}
Try this below code work with optional type -
class PayloadTest {
var label: String?
init(label:String) {
self.label = label
}
}

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'