Easy-Game-Center Sprite-Kit Integration - ios

I am trying to use the Easy-Game-Center by DaRkD0G from GitHub in my game (swift sprite kit). However, when calling the EasyGameCenter.Swift (using
EasyGameCenter.sharedInstance(self)
in my GameScene)
I get an error saying "Cannot convert value of type 'GameScene' to expected argument type 'UIViewController'". For the past couple days, I have tried changing up the different class types in EasyGameCenter but always get answers. Does anyone have any suggestions?

I'm the creator of this project.
You can't use the Game Center of Apple without UIViewController !
The Framework Game Center need UIViewController for work, this is the official documentation of Game Center Apple.
And Easy Game Center need create with delegate UIViewController for work perfectly, without it is impossible to use Game Center
Example projet Game Center + Sprite Kit :
http://www.raywenderlich.com/60980/game-center-tutorial-how-to-make-a-simple-multiplayer-game-with-sprite-kit-part-1
Create instance with UIViewController :
This is for create the instance of EasyGameCenter
override func viewDidLoad() {
super.viewDidLoad()
EasyGameCenter.sharedInstance(self)
}
Add this, if you change UIViewController for notifies the view controller delegate was changed, it's optional if you not change UIViewController you do not need this method
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
EasyGameCenter.delegate = self
}
just like that, now you can import the project with CocoaPods
pod 'EasyGameCenter', :git => 'https://github.com/DaRkD0G/Easy-Game-Center-Swift.git'

Never used that library, but as message says :
"Cannot convert value of type 'GameScene' to expected argument type
'UIViewController'"
This is the method you are calling:
class func sharedInstance(delegate:UIViewController)-> EasyGameCenter {
if Static.instance == nil {
dispatch_once(&Static.onceToken) {
Static.instance = EasyGameCenter()
Static.delegate = delegate
Static.instance!.loginPlayerToGameCenter()
}
}
return Static.instance!
}
You have to pass an UIViewController as an argument instead of GameScene.

Related

IBOutlet crashing with EXC_BAD_ACCESS even though not nil

In a UIViewController (rolePageController) I configure another UIViewController (drawerController) and pass it 2 UIViews from the role page that will be part of the drawerController's configuration. As soon as the drawerController tries to access the IBOutlet views from the rolePageController, it crashes with EXC_BAD_ACCESS (code=EXC_I386_GPFLT).
In the 1st VC (rolePageController), here are the IBOutlets:
#IBOutlet var rolePageDrawerView: UIView!
#IBOutlet var rolePageContentView: UIView!
In rolePageController.viewDidLoad() I make a call to the drawerController.configureDrawer(...):
override func viewDidLoad() {
super.viewDidLoad()
//other stuff happens here
let drawerController = UIStoryboard(name: "StoryboardName", bundle: nil).instantiateViewController(withIdentifier: "drawerController") as! DrawerViewController
drawerController.configureDrawer(drawerContainerView: self.rolePageDrawerView, overlaidView: self.rolePageContentView)
//other stuff here
}
The DrawerViewController protocol is defined as:
protocol DrawerViewController where Self: UIViewController {
func configureDrawer(drawerContainerView: UIView, overlaidView: UIView)
}
Here is the code for the configureDrawer(...) func:
private var drawerParentView: UIView!
private var overlaidByDrawerView: UIView!
func configureDrawer(drawerContainerView: UIView, overlaidView: UIView) {
self.drawerParentView = drawerContainerView
self.overlaidByDrawerView = overlaidView
}
Noticed in the debugger that the drawerController instance that is called does not match the self instance that receives the call. Here is the address of the instance that will be called:
Here is the address of the instance when I step into the call:
The address of drawerController before the call is not the address of self when I step into the call. That should never happen.
I have created a simplified project that reproduces the crash at https://github.com/ksoftllc/DynamicStackBufferOverflow.
Solution
Solution turned out to be to remove the where clause from the DrawerViewController protocol.
protocol DrawerViewController where Self: UIViewController {
func configureDrawer(drawerContainerView: UIView, overlaidView: UIView)
}
Found the offending code, but I don't know why this would cause the errors I was seeing. The drawerController conforms to DrawerViewController protocol, defined as:
protocol DrawerViewController where Self: UIViewController {
func configureDrawer(drawerContainerView: UIView, overlaidView: UIView)
}
When I remove the Where condition, it no longer crashes.
protocol DrawerViewController {
func configureDrawer(drawerContainerView: UIView, overlaidView: UIView)
}
The where clause was not actually necessary for correct function of the program, so I will proceed without it.
UPDATE
I filed a bug with swift.org and received a response. Adding a where clause to a protocol is not supported in Swift 4.2, but will be supported in Swift 5.0. In addition, #J Doe posted below a way to accomplish this with an update to Xcode toolkit.
dynamic-stack-buffer-overflow doesn't have anything to do with recursion. It means an alloca buffer was overrun. Check the asan runtime source code.
Suppose the stack is laid out so that you have an alloca buffer followed by an object pointer—maybe even one of the object pointers passed as an argument.
Suppose the alloca buffer gets overrun. In an asan build, this can trigger a dynamic-stack-buffer-overflow error. But in a non-asan build, it just writes over the bytes of that object pointer. Suppose it writes bytes that form an address that's not mapped in your process's page table.
If the program tries to read that object pointer and store it elsewhere (say, in an instance variable), it has to increment the reference count of the object. But that means dereferencing the pointer—and the pointer points to an unmapped address. Perhaps that's leading to a general protection fault, which Mach calls an EXC_I386_GPFLT.
It would be helpful if you posted the stack trace of the asan dynamic-stack-buffer-overflow error, and the disassembly of the code leading up to the error.
It really looks like Swift compiler bug. I simplified your code for clarification:
func foo(_ wow: TestProtocol) {
wow.foo()
}
protocol TestProtocol where Self: NSObject {
func foo()
}
class TestClass: NSObject, TestProtocol {
func foo() {
print("Much wow")
}
}
foo(TestClass())
You can report this as bug. To resolve this issue I propose you not use where statement or pass object with it's type func foo(_ wow: TestClass {.
To fix your issue, run it on the development trunk toolchain snapshot. You can download it here:
https://swift.org/download/
Go to Snapshots -> Trunk Development (master) XCode (so not Swift 5.0) and download the snapshot as of 15 December (I got the one from 30 November, but I am sure 15 December will work as well.)
After you installed the toolchain, in XCode go to: File -> Preferences -> Components and select the newest toolchain. It now runs without any crash.
Also, the where Self: UIViewController can be shorten to :UIViewcontroller (This only works on the newest toolchains):
protocol DrawerViewController: UIViewController {
func configureDrawer(drawerContainerView: UIView, overlaidView: UIView)
}
Had a similar issue today. For some reason, it was only occurring on the latest macOS.
The reason was that I hadn't specified a correct subclass for one of my IBOutlet in Storyboard.
The funny thing is that exc_bad_access occurred on another IBOutlet, albeit a subview of the one which wasn't appropriately specified. So, all in all, someone may find it helpful to check that all subclasses of IBOutlets are correctly specified in Storyboard :)
Move this Function Call from viewDidLoad to viewWillAppear
drawerController.configureDrawer(drawerContainerView: self.rolePageDrawerView, overlaidView: self.rolePageContentView)

Is there a way to have a custom class act on a UIView without having the ViewController passed (as reference) upon its initialization?

Example: I have a SpeechSynthesizer class that needs to update something in my UIView when it’s done uttering a piece of text. Since the SpeechSynthesizer class conforms to protocol AVSpeechSynthesizerDelegate, it is the one that receives the didFinish signal when the uttering has been completed. The idea here is to keep the ViewController from having too many delegate methods and a long list of protocols to conform to. The workaround I found was to have the ViewController passed in as a SpeechSynthesizer initialization parameter. This way I get to access the ViewController connected to the UIView I want to update from inside the SpeechSynthesizer class. The thing I don’t like about it is that it looks kind of ugly to have the ViewController passed in as a parameter to every single class that needs to use it. So I wonder, which other way I could accomplish this.
I suppose another way to ask the question is: How can I make the function
private func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance)
return something to a ViewController since it's not "called" by it?
I added a reply on Quora. Copying it here:
After doing some research and testing on code of my own here are 2 solutions to this problem.
Solution 1: The Delegate Pattern:
Create a custom delegate protocol in the ViewController
protocol ViewControllerDelegate:class {
func getViewLayer() -> CALayer
}
The ViewController must conform to this newly created protocol and therefore implement all the functions defined by it, so somewhere in the class ViewController you add:
public func getViewLayer() -> CALayer {
return self.view.layer
}
Then on my custom class, ReadTextMachine, I added a variable of the ViewControllerDelegate type
private weak var viewControllerDelegate: ViewControllerDelegate?
The variable must be weak and protocol must be of type class in order to solve a “retain cycle” problem (since both the custom class and the ViewController will point to each other)
You’ll notice now that the function call inside the ViewController is already “callable” from the custom class, so in my ReadTextMachine I added:
let viewLayer = self.viewControllerDelegate?.getViewLayer()
self.cameraPreview = CameraPreview(session: self.camera.getSession(), container: viewLayer!)
self.cameraPreview?.addPreview()
In the above case, my CameraPreview (yes, a 3rd class in this example) simply adds a camera preview layer on the UIView. For that it needed access to the main View’s layer.
The above code still doesn’t work because our original viewController’s instance hasn’t been passed as reference anywhere in our code. For that we add the following function in ReadTextMachine:
public func setViewControllerDelegate(viewController: ViewController) { // call this from the ViewController so that ViewController can be accessed from here.
self.viewControllerDelegate = viewController
}
The above piece of code will have to be called from the ViewController, after we instantiate our custom class (ReadTextMachine), so that the viewControllerDelegate inside it points to the ViewController. So in our ViewController.swift:
operatingMode = ReadTextMachine()
operatingMode.setViewControllerDelegate(viewController: self)
Another example and explanation can be found in this video from LetsBuildThatApp. I derived my solution mostly from it.
My current app in development applying the above solution can be found here: agu3rra/World-Aloud
Solution 2: Notifications and Observers pattern
This one is a bit easier to understand and follow. The general idea is to have your custom class broadcast a message which triggers a function call on your ViewController since it has an observer setup, waiting to hear that message.
So to give an example, in the context I used it, I have a CameraCapture class which uses AVFoundation to capture a photo. The capture photo trigger cannot immediately return an image, since iOS has a set of steps to execute before actually generating an image. I wanted my ReadTextMachine to resume an activity after CameraCapture had a photo available. (To apply this in the context of the CustomClass triggers ViewController event is basically the same, since both are actual classes in an iOS app as well).
So the 1st thing I did was create a broadcast function since I would use it in many places in my app. I simply placed it in a Utilities.swift file in the Xcode project.
public func broadcastNotification(name: String) {
let notification = Notification.Name(rawValue: name)
NotificationCenter.default.post(name: notification, object: nil)
}
The above function takes a string, which must be a unique notification identifier, and broadcasts it thru NotificationCenter.
In my CameraCapture class, I added a static constant to reference the unique identifier of the message:
static let NOTIFY_PHOTO_CAPTURED = "agu3rra.worldAloud.photo.captured"
For those who know AVFoundation, a photo is available when event didFinishProcessingPhoto gets executed, so at the end of that I added:
broadcastNotification(name: CameraCapture.NOTIFY_PHOTO_CAPTURED)
The above is a call to my previously defined utility function.
For my ReadTextMachine class to be able to catch that notification, I added the following on its init() and deinit routines:
override init() {
super.init()
// Setup event observers
let notification1 = Notification.Name(rawValue: CameraCapture.NOTIFY_PHOTO_CAPTURED)
NotificationCenter.default.addObserver(self,
selector: #selector(self.processingDoneTakingPhoto),
name: notification1,
object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self) // cleanup observer once instance no longer exists
}
Removing the observer is important at deinit so that when your object is deallocated from memory, the observer isn’t left lingering around. The above configured observer triggers a function call inside ReadTextMachine:
#IBAction private func processingDoneTakingPhoto() {
// does my stuff
}
That’s it! Again, the entire Xcode project can be downloaded from my project’s Git repository: agu3rra/World-Aloud
Hope this can be of use to others.
Cheers!

Swift: Fatal error: unexpectedly found nil while unwrapping an Optional value (SpriteKit)

I've just started learning to program iOS games with SpriteKit and I'm a novice to programming (I have only programmed in Java and Swift before this). I started out by doing a tutorial I found online. I'm at the point where I am trying to add a "Game Over" scene, and I keep getting the error
"Thread 1:EXC-BAD_INSTRUCTION(code=EXC_I386_INVOP,subcode=0x0)"
when I am declaring the gameOverLabel constant. It compiles but crashes at run time as soon as the ball hits the bottom of the screen, which is supposed to trigger the 'Game Over' screen.
import SpriteKit
let gameOverLabelCategoryName = "gameOverLabel"
class GameOverScene: SKScene {
var gameWon: Bool = false {
didSet {
let gameOverLabel = childNodeWithName(gameOverLabelCategoryName) as! SKLabelNode
gameOverLabel.text = gameWon ? "Game Won" : "Game Over"
}
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
if let view = view {
let gameScene = GameScene.unarchiveFromFile("GameScene") as! GameScene
view.presentScene(gameScene)
}
}
}
Also if anyone has suggestions of places I can go to learn more about SpriteKit, articles or videos, it would be much appreciated as most things I have found have been in Objective-C and I am doing this in Swift.
Here is the tutorial I have been following..
childNodeWithName will return nil if a node with that name does not exist. Your code is not checking for this possibility (the as! assumes that it is both not nil and of the appropriate type) so this is causing the crash.
The tutorial asks you to create this 'gameOverLabel' node and name it before creating this code. Check that you did that correctly and that you did not misname it (it is case sensitive for example).
It looks like you are declaring your gameOverLabelCategoryName constant outside of the scope of the class which looks a bit odd, but should be fine. It will be scoped to internal (docs).
On line 14: "if let view = view {" you are declaring a constant named view which masks the original self.view instance. Perhaps that could be confusing the compiler and causing an internal crash?

Assigning Functions from other Classes in Swift

Is it possible to access and run a specific method/function from another class that can change dynamically as the app is run?
I’ll try to simplify the problem as much as possible.
SelectionPage.swift
Choose which class needs to be selected and accessed using an UIPickerView - 10 possible selections (Class1, Class2, Class3,…, Class10).
Class1.swift, Class2.swift, … Class10.swift
Each of the 10 classes has a single method that has exactly the same name but is programmed differently:
func runOnUpdate() { }
GameSceneViewController.swift
When a selection is made on the SelectionPage, the app segues to a GameSceneViewController where the specific selected function is run every time the update function is run:
override func update(currentTime: CFTimeInterval)
{
// run runOnUpdate() function here from selected class
}
Inside the update function, I would like to execute the runOnUpdate( ) function depending on which class was selected on the SelectionPage. Is this possible? Ideally I'd like to be able to assign the specific class/method in the:
override func didMoveToView(view: SKView)
so that I can access in other functions as well.
I’ve looked into lazy instantiation, creating delegates for each of the classes, #objc(Class1), arrays of [AnyClass], typealias, global variables in structs, singletons etc. but I’m unable to figure out how to make this work.
It seems like a fairly common problem so any help would be greatly appreciated! Thank you in advance!
You were correct in trying delegates as this is a case where you should make a protocol and a delegate. The protocol requires the function. From there you set the delegate property to an instance of a class that conforms to that protocol and then you call delegate?.someFunction() to call the function on the given object.
class ViewController: UIViewController {
var delegate: Updatable?
override func viewDidLoad() {
super.viewDidLoad()
let foo = Foo()
delegate = foo
delegate?.runOnUpdate() // prints do something
}
}
protocol Updatable {
func runOnUpdate()
}
class Foo: NSObject, Updatable {
func runOnUpdate() {
println("do something")
}
}

Delegate Error in Swift

I am trying to send a double value from a UIView (which is loaded from a XIB) to a ViewController using a delegate
Here is my protocol, it is just sending a double to the main ViewController on a button click.
protocol HoursWorkedDelegate{
func sendHoursWorked(hoursWorked: Double);
}
class HoursWorkedView: UIView{
var delegate: HoursWorkedDelegate?;
#IBAction func calculateHoursWorked(sender: AnyObject){
// Do some calculations for the hoursWorked value
// Give value
delegate!.sendHoursWorked(hoursWorked);
}
}
// This class now wants that Double value
class ViewController: UIViewController, HoursWorkedDelegate{
// Conform to protocol
func sendHoursWorked(hoursWorked: Double){
// Lets say we just want to assign this value to a textField
hoursWorkedTextField.text = NSString(format: "%.4f", hoursWorked);
}
}
The error message I get is Thread 1: EXC_BAD_INSTRUCTION(code = EXC_I386_INVOP, subcode=0x0)
Any help would be much appreciated, Thank You!
As a start, change the exclamation point in this snippet to a question mark:
delegate!.sendHoursWorked(hoursWorked);
This is what's likely causing the crash, as you are force-unwrapping the optional delegate property. A question mark means we'll only call sendHoursWorked() on the delegate if the delegate exists.
That fix will now probably mean that your program is no longer crashing, but you still don't get the desired results, because sendHoursWorked() is never called. We have to tell our HoursWorkedView object who is delegating it.
Somewhere in your code, you might have something like this:
let hoursWorkedView = HoursWorkedView()
self.view.addSubview(hoursWorkedView)
It's right here where we should be setting the delegate:
let hoursWorkedView = HoursWorkedView()
hoursWorkedView.delegate = self
self.view.addSubview(hoursWorkedView)
Though if it's me, I probably add a constructor to HoursWorkedView that accepts the delegate property:
init(delegate: HoursWorkedDelegate) {
super.init()
self.delegate = delegate
}
And now we can just do this:
let hoursWorkedView = HoursWorkedView(delegate: self)
self.view.addSubview(hoursWorkedView)
I think you're getting your view and your viewcontroller mixed up: a ViewController controls things; a view just displays them. The viewController tells the view what to display.
So, you want to connect your button to the viewController -- not the view. And you don't need a custom view class or a delegate.
Set it up like this:
create a textField and a button
create an outlet for the textField
put calculateHoursWorked directly in your viewController
create an action to connect the button to calculateHoursWorked
in calculateHoursWorked, set self.textField.text to the result of the calculation (where "textField" is whatever you named your outlet)
You wouldn't use a delegate in this context because the viewController knows everything the view does. The delegate pattern is for cases where one object has no visibility into another.
EDIT:
That being said, the bug here is that the delegate isn't actually being set anywhere.
Swift Optionals (the ! and ?) help prevent cases like this. If you explicitly unwrap an optional using !, you have to make sure it's always defined. In this case, since delegate is defined as optional (?) you have to check it:
#IBAction func calculateHoursWorked(sender: AnyObject){
// Do some calculations for the hoursWorked value
// Give value
if let currentDelegate = self.delegate {
currentDelegate.sendHoursWorked(hoursWorked)
}
}

Resources