Gameplaykit GKState, swift func with two parameters - ios

I'm sure that is a simple question for you.
How can I write a func with two parameters with one GKState?
UPDATE
Apple use
func willExitWithNextState(_ nextState: GKState)
If I use somefunc(state:GKState) works fine
while somefunc(state:GKState, string:String) does't work, why???
Other example
I've tried this:
class Pippo:GKState {}
//1
func printState (state: GKState?) {
print(state)
}
printState(Pippo) //Error cannot convert value of type '(Pippo).Type' (aka 'Pippo.Type') to expected argument type 'GKState?'
//2
func printStateAny (state: AnyClass?) {
print(state)
}
printStateAny(Pippo) //NO Error
//3
func printStateGeneral <T>(state: T?) {
print(state)
}
printStateGeneral(Pippo) //No Error
//4
func printStateAnyAndString (state: AnyClass?, string:String) {
print(state)
print(string)
}
printStateAnyAndString(Pippo/*ExpectedName Or costructor*/, string: "Hello") //ERROR
printStateAnyAndString(Pippo()/*ExpectedName Or costructor*/, string: "Hello") //ERROR cannot convert value of type 'Pippo' to expected argument type 'AnyClass?'
SOLUTION THANKS #0x141E
func printStateAnyAndString (state: GKState.Type, string:String) {
switch state {
case is Pippo.Type:
print("pippo")
default:
print(string)
}
}
printStateAnyAndString(Pippo.self, string: "Not Pippo")
Thanks for reply

If you want a parameter to be a class, use Class.Type or AnyClass
func printState (state: AnyClass, string:String) {
print(state)
print(string)
}
and use Class.self as the argument
printState(Pippo.self, string:"hello pippo")
Update
If your function definition is
func printState (state:GKState, string:String) {
if state.isValidNextState(state.dynamicType) {
print("\(state.dynamicType) is valid")
}
print(state)
print(string)
}
you'll need to pass in an instance of GKState (or a subclass of GKState) as the first argument, not the class/subclass itself. For example,
let pippo = Pippo()
printState (pippo, "Hello")

Throughout your sample code you have used AnyClass, whereas you should (probably) be using AnyObject. AnyClass refers to a class definition, whereas AnyObject is an instance of a class.
class MyClass { }
func myFunc1(class: AnyClass)
func myFunc2(object: AnyObject)
let myObject = MyClass() // create instance of class
myFunc1(MyClass) // myFunc1 is called with a class
myFunc2(myObject) // myFunc2 is called with an instance
You have also made most of your parameters Optionals with the "?", whereas it doesn't look required. For example:
printState(nil) // What should this do?

Related

swift protocol conformance with duplicate function names

class A {
func test(string: String, another defaultValue: String = "") {
///...
}
}
class B {
func test(string: String, different defaultValue: Bool = true) {
///...
}
}
protocol Test {
func test(string: String)
}
extension A: Test {
func test(string: String) {
self.test(string: string)
}
}
extension B: Test {
func test(string: String) {
self.test(string: string)
}
}
When I do this I get the following error
Function call causes an infinite recursion
How to confirm to the protocol Test to the classes which have similar function names
When A or B conform to Test, there is no way for the program to know which .test you're calling, cause the internal .test methods in A & B have default values.
To resolve the ambiguity, you can be specific:
extension A: Test {
func test(string: String) {
self.test(string: string, another: "")
}
}
extension B: Test {
func test(string: String) {
self.test(string: string, different: true)
}
}
You have to call class methods with full signature:
extension A: Test {
func test(string: String) {
self.test(string: string, another: "")
}
}
extension B: Test {
func test(string: String) {
self.test(string: string, different: true)
}
}
As swift allows method overloading, you may use the same function name with different signatures.
In your example class methods have different signatures, comparing to the protocol methods, so it is fine. However class methods have default values and can be called without full signature and in this case it is ambiguous as the signature become the same.

Get the name of class & function sent to another class [duplicate]

here is a scenario
func callingMethod_A {
self.someCalculation()
}
func callingMethod_B{
self.someCalculation()
}
func someCalculation{
//how to find who called this method? is it callingMethod_A or _B at runtime?
//bla bla
}
how can we get the method name that called it during run time.
thank you.
I worked out a way to do this, for Swift code anyway:
Define a String parameter callingFunction and give it a default value of #function. Do not pass anything from the caller and the compiler provides the calling function name.
Building on #Anu.Krthik's answer:
func someCalculation (parameter: String, callingMethod: String = #function ) {
print("In `\(#function)`, called by `\(callingMethod)`")
}
func foo(string: String) {
someCalculation(parameter: string)
}
foo(string: "bar")
The above prints
In `someCalculation(parameter:callingMethod:)`, called by `foo(string:)`
However, beware that this technique can be subverted if the caller provides a value for the callingFunction parameter. if you call it with:
func foo(string: String) {
someCalculation(parameter: string, callingMethod: "bogusFunctionName()")
}
You get the output
In `someCalculation(parameter:callingMethod:)`, called by `bogusFunctionName()`
instead.
You can use Thread.callStackSymbols like this
func callingMethod_A() {
self.someCalculation()
}
func callingMethod_B(){
self.someCalculation()
}
func someCalculation(){
let origin = Thread.callStackSymbols
print(origin[0])
print(origin[1])
}

How to identify calling method from a called method in swift

here is a scenario
func callingMethod_A {
self.someCalculation()
}
func callingMethod_B{
self.someCalculation()
}
func someCalculation{
//how to find who called this method? is it callingMethod_A or _B at runtime?
//bla bla
}
how can we get the method name that called it during run time.
thank you.
I worked out a way to do this, for Swift code anyway:
Define a String parameter callingFunction and give it a default value of #function. Do not pass anything from the caller and the compiler provides the calling function name.
Building on #Anu.Krthik's answer:
func someCalculation (parameter: String, callingMethod: String = #function ) {
print("In `\(#function)`, called by `\(callingMethod)`")
}
func foo(string: String) {
someCalculation(parameter: string)
}
foo(string: "bar")
The above prints
In `someCalculation(parameter:callingMethod:)`, called by `foo(string:)`
However, beware that this technique can be subverted if the caller provides a value for the callingFunction parameter. if you call it with:
func foo(string: String) {
someCalculation(parameter: string, callingMethod: "bogusFunctionName()")
}
You get the output
In `someCalculation(parameter:callingMethod:)`, called by `bogusFunctionName()`
instead.
You can use Thread.callStackSymbols like this
func callingMethod_A() {
self.someCalculation()
}
func callingMethod_B(){
self.someCalculation()
}
func someCalculation(){
let origin = Thread.callStackSymbols
print(origin[0])
print(origin[1])
}

Passing closures to Private API's

I'm trying to fetch all the available airplay devices from the private API MPAVRoutingController. I'm using a third party perform selector library for swift called performSelector-Swift. The method I am trying to call is fetchAvailableRoutesWithCompletionHandler. This takes one parameter, an objective-c block. - (void)fetchAvailableRoutesWithCompletionHandler:(id /* block */)arg1; When I try and pass in a closure I get a compile error and if I don't pass anything in my app crashes. I'm not releasing this app and thats why I'm using the priv API.
let MPAVRoutingController = NSClassFromString("MPAVRoutingController")! as! NSObject.Type
let routingController = MPAVRoutingController.init()
if let availableRoutes = routingController.swift_performSelector("fetchAvailableRoutesWithCompletionHandler:", withObject: {
object in
}) {
print(availableRoutes)
}
First.. How I found the correct completion block signature: http://i.imgur.com/UGVayPE.png
That shows that it allocates an NSMutableArray as the parameter to the completion block when it invokes it. That's the only parameter. You don't have to do this (disassemble it). Upon an exception being thrown, you can print the signature. Sometimes it will also tell you which kind of block is expected.
Next, my opinion on invoking selectors dynamically..
Your best option is to not perform selectors.. It's a pain especially when the call contains MULTIPLE parameters..
What you can do is invocation through interface/extension pointers.. I do this in C++ (Idea from the Pimpl idiom.. COMM interfaces do this too) all the time and it works with Swift, Objective-C, Java.. etc..
Create a protocol that has the same interface as the object. Create an extension that inherits that protocol. Then cast the object instance to that extension/interface/protocol.
Call whatever function you want via the interface/extension/protocol pointer.
import UIKit
import MediaPlayer
#objc
protocol MPAProtocol { //Functions must be optional. That way you don't implement their body when you create the extension.
optional func availableRoutes() -> NSArray
optional func discoveryMode() -> Int
optional func fetchAvailableRoutesWithCompletionHandler(completion: (routes: NSArray) -> Void)
optional func name() -> NSString
}
extension NSObject : MPAProtocol { //Needed otherwise casting will fail!
//Do NOT implement the body of the functions from the protocol.
}
Usage:
let MPAVRoutingControllerClass: NSObject.Type = NSClassFromString("MPAVRoutingController") as! NSObject.Type
let MPAVRoutingController: MPAProtocol = MPAVRoutingControllerClass.init() as MPAProtocol
MPAVRoutingController.fetchAvailableRoutesWithCompletionHandler! { (routes) in
print(routes);
}
If you were to do it with a Bridging header instead of creating the extension + protocol, you'd just do a single Objective-C category:
#import <Foundation/Foundation.h>
#interface NSObject (MPAVRoutingControllerProtocol)
- (void)fetchAvailableRoutesWithCompletionHandler:(void(^)(NSArray *routes))completion;
#end
#implementation NSObject (MPAVRoutingControllerProtocol)
#end
Then:
let MPAVRoutingControllerClass: NSObject.Type = NSClassFromString("MPAVRoutingController") as! NSObject.Type
let MPAVRoutingController = MPAVRoutingControllerClass.init()
MPAVRoutingController.fetchAvailableRoutesWithCompletionHandler! { (routes) in
print(routes);
}
Finally, if you can use protocol injection, you can do this much easier:
func classFromString(cls: String, interface: Protocol?) -> NSObject.Type? {
guard let interface = interface else {
return NSClassFromString(cls) as? NSObject.Type
}
if let cls = NSClassFromString(cls) {
if class_conformsToProtocol(cls, interface) {
return cls as? NSObject.Type
}
if class_addProtocol(cls, interface) {
return cls as? NSObject.Type
}
}
return nil
}
func instanceFromString<T>(cls: String, interface: Protocol?) -> T? {
return classFromString(cls, interface: interface)?.init() as? T
}
#objc
protocol MPAProtocol {
optional func availableRoutes() -> NSArray
optional func discoveryMode() -> Int
optional func fetchAvailableRoutesWithCompletionHandler(completion: (routes: NSArray) -> Void)
optional func name() -> NSString
}
let MPAVRoutingController: MPAProtocol = instanceFromString("MPAVRoutingController", interface: MPAProtocol.self)!
MPAVRoutingController.fetchAvailableRoutesWithCompletionHandler! { (routes) in
print(routes);
}

Returning Generic.Type for later use with class methods

Is it possible to return a type of generic that conforms to protocol for later use with class functions using Swift 1.2? Take a look:
protocol SomeProtocol
{
static func start(kind: Kind)
}
class A: SomeProtocol
{
class func start(kind: Kind)
{
print("A started")
}
}
class B: SomeProtocol
{
class func start(kind: Kind)
{
print("B started")
}
}
enum Kind {
case Akind
case Bkind
private func classKind<T: SomeProtocol>() -> T.Type
{
switch self {
case .Akind: return A.self
case .Bkind: return B.self
}
}
func doSomething() {
self.classKind().start(self)
}
}
I tried various methods but every of them ended with some errors. Currently I got 'A' is not a subtype of 'T' in classKind method (same for 'B') and cannot invoke 'start' with an argument list of type '(Kind)' in doSomething.
I'm sure I'm pretty close but can't solve it...
If you're using Swift 2, to achieve what you want you only need to change:
private func classKind<T: SomeProtocol>() -> T.Type { ... }
to
private func classKind() -> SomeProtocol.Type { ... }
Now back to the not-working code to see where the errors were coming from. You don't need to make the changes I'm now detailing, this is just to explain the errors.
First examine your doSomething method:
func doSomething() {
self.classKind().start(self)
// Error: Argument for generic parameter 'T' could not be inferred.
//
// (I'm using Xcode 7 b6, which may explain the differing error messages)
}
For the type returned by classKind to be inferred, you'd have to do:
let type: A.Type = self.classKind() // Or you could use `B.Type`.
type.start(self)
Which obviously defeats the point of your goal, since you have to specify the type you want.
Secondly, the errors in classKind:
private func classKind<T: SomeProtocol>() -> T.Type
{
switch self {
case .Akind: return A.self
// Cannot convert return expression of type 'A.Type' to return type 'T.Type'.
case .Bkind: return B.self
// Cannot convert return expression of type 'B.Type' to return type 'T.Type'.
}
}
To see why this doesn't work consider the following example, in which I have another type that conforms to SomeProtocol:
struct C: SomeProtocol { ... }
Then in doSomething:
func doSomething() {
let type: C.Type = self.classKind()
type.start(self)
}
The errors you're getting can now be read as: Cannot convert return expression of type 'A.Type'/'B.Type' to return type 'C.Type'.

Resources