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()
Related
I'm using Xcode 9.4.1 with Swift 4.1 on iOS 11.4.1.
I've got a handful of protocols, like this:
protocol Bla {
// some stuff
}
protocol Gorp {
// some other stuff
}
And I've got some structs that conform to both of those protocols, like this:
typealias MyType = Bla & Gorp
struct Hello: MyType {
var ID: Int
var name: String
}
struct Goodbye: MyType {
var percentage: Double
var hairbrush: String
}
Then I've got a func that takes an argument, theType, which conforms to both Bla & Gorp. In this example, I'm just printing a description -- like this:
func doSomething<T: MyType>(_ theType: T.Type) {
// some stuff
print("Got called... \(theType)")
}
And, I can call this function passing each of the two struct types (Hello and Goodbye), like this:
doSomething(Hello.self)
doSomething(Goodbye.self)
This works great and I get the following output, as expected:
Got called... Hello
Got called... Goodbye
However, what I'd really like to do is to iterate over a bunch of these, rather than calling them individually.
This way gives me an error "note: expected an argument list of type '(T.Type)'":
for thingy in [Hello.self, Goodbye.self] {
doSomething(thingy)
}
If I add an as! [MyType.Type] or as! [MyType], I get the same error. I've also tried this:
for thingy in [Hello.self as MyType.Type, Goodbye.self as MyType.Type] {
doSomething(thingy)
}
Same error as the rest.
I've also tried without the typealias.
If I start typing, the autocomplete says that doSomething is expecting an argument of type (Bla & Gorp).Protocol. So, I also tried this:
for thingy in [Hello.self, Goodbye.self] as! [(Bla & Gorp).Protocol] {
doSomething(thingy)
}
In this case, I get the message:
In argument type '(Bla & Gorp).Protocol', 'Bla & Gorp' does not conform to expected type 'Bla'
Also tried this sort of thing, which gave an error, "Cannot invoke 'doSomething' with an argument list of type '(MyType.Type)'":
struct AnyBlaGorp {
let blaGorp: MyType.Type
init<T: MyType>(_ theType: T.Type) {
self.blaGorp = theType
}
}
for thingy in [AnyBlaGorp(Hello.self), AnyBlaGorp(Goodbye.self)] {
doSomething(thingy.blaGorp)
}
Pointers to the magical correct syntax would be greatly appreciated. :)
You can make the doSomething method non-generic and accept a MyType.Type. You can only do this if your protocols don't have Self or associated types.
func doSomething(_ theType: MyType.Type) {
// some stuff
print("Got called... \(theType)")
}
Next, you cast the array to a [MyType.Type]:
for thingy in [Hello.self, Goodbye.self] as [MyType.Type] {
doSomething(thingy)
}
This makes use of the fact that A.self can be converted to the type B.Type if A inherits from/conforms to B.
Is it possible to create a keypath referencing a method? all examples are paths to variables.
I'm trying this:
class MyClass {
init() {
let myKeypath = \MyClass.handleMainAction
...
}
func handleMainAction() {...}
}
but it does not compile saying Key path cannot refer to instance method 'handleMainAction()
KeyPaths are for properties. However, you can do effectively the same thing. Because functions are first class types in swift, you can create a reference to handleMainAction and pass it around:
//: Playground - noun: a place where people can play
import UIKit
import XCTest
import PlaygroundSupport
class MyClass {
var bar = 0
private func handleMainAction() -> Int {
bar = bar + 1
return bar
}
func getMyMainAction() -> ()->Int {
return self.handleMainAction
}
}
class AnotherClass {
func runSomeoneElsesBarFunc(passedFunction:() -> Int) {
let result = passedFunction()
print("What I got was \(result)")
}
}
let myInst = MyClass()
let anotherInst = AnotherClass()
let barFunc = myInst.getMyMainAction()
anotherInst.runSomeoneElsesBarFunc(passedFunction: barFunc)
anotherInst.runSomeoneElsesBarFunc(passedFunction: barFunc)
anotherInst.runSomeoneElsesBarFunc(passedFunction: barFunc)
This will work fine, and you can pass "barFunc" to any other class or method and it can be used.
You can use MyClass.handleMainAction as an indirect reference. It gives you a block that take the class instance as the input parameter, and returns corresponding instance method.
let ref = MyClass.handleMainAction //a block that returns the instance method
let myInstance = MyClass()
let instanceMethod = ref(myInstance)
instanceMethod() //invoke the instance method
The point is you can pass around / store the method reference just like what you did with a key path. You just need to supply the actual instance when you need to invoke the method.
It's not a duplicate cause with lazy i have an issu too :
"A C function pointer cannot be formed from a closure that captures context"
In my main class I have "detectChangeMidi" but in this code, when I try to call a function I don't understand why I can't.
(i can't use var too, anything of my class)
I'm not expert in swift, then try to explain to me what's going one.
I use the CoreMidi librarie.
UPDATE :
I replace the code by minimaliste code for better entendement.
import Foundation
import CoreMIDI
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
gestionMidi()
//...
}
func gestionMidi() {
//...
let midiNotif:MIDINotifyProc = detectChangeMidi
MIDIClientCreate("Swift3 Test Client" as CFString, midiNotif, nil, &midiClient)
//...
}
func plop(){
print("bla bla bla")
}
let detectChangeMidi: #convention(c) (UnsafePointer<MIDINotification>, UnsafeMutableRawPointer?) -> Swift.Void =
{ midiNotification,unkown in
var notification = midiNotification.pointee
self.plop() //problem here
//...
}
}
Your entire agenda here is misguided; it is not at all obvious what you can be trying to do. You cannot declare a property or function as being convention(c) and also refer to self. But you don't need to! If your goal is to pass a function as a parameter where a C pointer-to-function is expected, just pass the function. Anyway you'll have a much easier time in Swift if you call MIDIClientCreateWithBlock(_:_:_:) instead.
The problem is with the scope as I can judge from the error message.
Also the thing to get attention to is that you're executing plop() in closure, and that requires self.plop().
also midiNotification,unkown in - unkown seems to be a typo.
Check where you declare the function itself. From this snippet it's hard to understand what's your declaration scope.
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
}
}
I'm seeing some odd behaviour in a class I created a while ago, where it seems that a struct's properties are changing immediately after being passed (copied) to a method.
I've boiled it down to a simple test case that can be run in a playground:
struct StructToPass<T> {
let x: T
}
class MyClass<T> {
func createAndPassStructWithValue(value: T) {
let structToPass = StructToPass(x: value)
println("Before passing to method: \(structToPass.x)")
passStruct(structToPass)
}
func passStruct(_ theStruct: StructToPass<T>? = nil) {
println("Inside method: \(theStruct!.x)")
}
}
let myClass = MyClass<Int>()
myClass.createAndPassStructWithValue(42)
Looking at the relevant printed statements, it shows that the struct's x property has changed:
// Before passing to method: 42
// Inside method: 140734543799888
Creating the struct outside the class and calling passStruct(_:) directly causes the playground to crash, as does writing passStruct(_:) as a function:
// Causes playground to crash:
let aStruct = StructToPass(x: 42)
myClass.passStruct(aStruct)
// Also causes playground to crash:
func passStruct<T>(_ theStruct: StructToPass<T>? = nil) {}
passStruct(aStruct)
Changing the passStruct(_:) method/function to use the default external parameter name fixes the issue, as does introducing another parameter (before/after the default parameter):
// This works:
func passStruct<T>(theStruct: StructToPass<T>? = nil) {
println("Inside function: \(theStruct!.x)")
}
passStruct(theStruct: aStruct)
// This also works:
func passStruct<T>(_ theStruct: StructToPass<T>? = nil, someOtherParam: Int) {
println("Inside function: \(theStruct!.x)")
}
passStruct(aStruct, 42)
Is this a compiler bug? It seems the compiler doesn't like it when a generic function/method with a single argument with a default value doesn't use an external parameter name. It's a specific case, but I think it ought to work. If it shouldn't work, there ought to be a compiler warning.
110% compiler bug. I've even tried this out of Playground. It all happily compiles until you want to add a line which actually does something, like sending a passStruct. There's all kinds of things wrong with this. I even had this fail:
func passStruct<T>(_ theStruct: StructToPass<T>? = (nil as StructToPass<T>?)) {
println("Inside function: \(theStruct!.x)")
}
which I kinda thought might be the problem (even though it shouldn't be I've had that elsewhere).
Well found! Report it. They're clearly not finished with generics. In my experiments I found that generic class properties aren't allowed.
static let nilStruct: StructToPass<T>? = nil
does not compile, with one of the "not yet supported" error messages.