2017-03-27 4 views
3

私はスプライトキットとシーンを使ってXcodeでゲームを開発しました。今、TwitterやFacebookにハイスコアを投稿する機能を統合しようとしています。私は周りを見回して、ほとんどの人がSLComposeServiceViewControllerを使って、それを試してみるまで言います。私のアプリは実際にシーンを使用するだけなので、メンバー関数 "presentViewController(....)"を持つことはありません。したがって、私はそれを提示することはできません。誰もがこれを回避する方法を知っていますか?XcodeのシーンでFacebookとTwitterを統合するSwift iOS

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { 

    let touch:UITouch = touches.first! 
    let touchLocation = touch.location(in: self) 
    let touchedNode = self.atPoint(touchLocation) 

    if (touchedNode.name == "tryAgain") { 
     let nextScene = Scene_LiveGame(size: self.scene!.size) 
     nextScene.scaleMode = self.scaleMode 
     self.view?.presentScene(nextScene, transition: SKTransition.fade(withDuration: 0.5)) 
    } 
    else if (touchedNode.name == "share") { 

     if SLComposeViewController.isAvailable(forServiceType: SLServiceTypeFacebook) { 

     let fShare = SLComposeViewController(forServiceType: SLServiceTypeFacebook) 



     self.presentViewController(fShare!, animated: true, completion: nil) 
     //^This is where my problem is. Xcode is telling me that self has no member function presentViewController which I totally understand, because its a scene and thus doesn't share those functions. But every resource online has shown me this is the only way to do it 

     } 

    } 
+3

ご使用のコード(該当する部品)を記載してください。しかし、一般に、適切なView ControllerでView Controllerに依存するメソッドを指定し、それらのメソッドを呼び出す場面から通知を送信することができます。 – Whirlwind

+0

'else if'ブロックのコードは、通知を送信できるコードに置き換えてください。また、必要なメンバメソッドを持ち、前述の通知をリッスンする適切なView Controllerに移動する必要があります。 – Whirlwind

+0

私がフォローしているかどうかはわかりませんが、コードを私が作成したカスタムビューコントローラクラスに移動しましたが、私はまだシーンから呼び出すことができません。 – Matt

答えて

1

を助け希望をあなたのシーンからあなたのスコア値を使用して、例えば

ShareMenu.open( 
    text: "Can you beat my score \(self.score)?", 
    ... 
) 

テキストに追加することができます。 crashoverride777が提案したものとは別に、2つのテクニックを紹介します。だから、最初の技術は、このように、通知を使用して次のようになります。

GameScene:ここ

import SpriteKit 

let kNotificationName = "myNotificationName" 

class GameScene: SKScene { 


    private func postNotification(named name:String){ 

     NotificationCenter.default.post(
      Notification(name: Notification.Name(rawValue: name), 
         object: self, 
         userInfo: ["key":"value"])) 
    } 

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { 


     self.postNotification(named: kNotificationName) 

    } 
} 

は、あなたが画面をタップして通知を投稿してください。目的のビューコントローラクラスは、このように、この通知をリッスンすることができます:ここで

import UIKit 
import SpriteKit 

class GameViewController: UIViewController { 

    override func viewDidLoad() { 
     super.viewDidLoad() 


     NotificationCenter.default.addObserver(
      self, 
      selector: #selector(self.handle(notification:)), 
      name: NSNotification.Name(rawValue: kNotificationName), 
      object: nil) 

     if let view = self.view as! SKView? { 
      // Load the SKScene from 'GameScene.sks' 
      if let scene = GameScene(fileNamed: "GameScene") { 
       // Set the scale mode to scale to fit the window 
       scene.scaleMode = .aspectFill 

       // Present the scene 
       view.presentScene(scene) 
      } 
     } 
    } 

    func handle(notification:Notification){ 
     print("Notification : \(notification)") 
    } 
} 

が、私たちは、この通知のためのオブザーバーとしての自己を追加 - 通知が発生したときに、適切な取り扱いのメソッドが呼び出されることを意味し(それはあります私たちのカスタムhandle(notification:)メソッド。私は、代表団のための別の例を書きますクリーン:)私が言ったように

2

別のUIViewControllerからUIViewControllerを表示する必要があるため、このエラーが発生しています。したがって、自己(SKScene)はUIViewControllerではないため、

self.presentViewController(...) 

は動作しません。 SKSceneから提示するには、これを言う必要があります

view?.window?.rootViewController?.presentViewController(fShare!, animated: true, completion: nil) 

これらのAPIをもう使用しないことをお勧めします。あなたの共有ニーズに合わせてUIActivityViewControllerを使う方が良いです。この方法で、あなたのアプリには1つだけの共有ボタンが必要で、あらゆる種類のサービス(電子メール、Twitter、Facebook、iMessage、WhatsAppなど)に共有できます。

新しいSwiftファイルを作成し、このコードを追加します。

enum ShareMenu { 

    static func open(text: String, image: UIImage?, appStoreURL: String?, from viewController: UIViewController?) { 
     guard let viewController = viewController, let view = viewController.view else { return } 

    // Activity items 
    var activityItems = [Any]() 

    // Text 
    activityItems.append(text) 

    // Image 
    if let image = image { 
     activityItems.append(image) 
    } 

    /// App url 
    if let appStoreURL = appStoreURL { 
     let items = ActivityControllerItems(appStoreURL: appStoreURL) 
     activityItems.append(items) 
    } 

    // Activity controller 
    let activityController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil) 

    // iPad settings 
    if UIDevice.current.userInterfaceIdiom == .pad { 
     activityController.modalPresentationStyle = .popover 
     activityController.popoverPresentationController?.sourceView = view 
     activityController.popoverPresentationController?.sourceRect = CGRect(x: view.bounds.midX, y: view.bounds.midY, width: 0, height: 0) 
     activityController.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection.init(rawValue: 0) 
    } 

    // Excluded activity types 
    activityController.excludedActivityTypes = [ 
     .airDrop, 
     .print, 
     .assignToContact, 
     .addToReadingList, 
    ] 

    // Present 
    DispatchQueue.main.async { 
     viewController.present(activityController, animated: true) 
    } 

    // Completion handler 
    activityController.completionWithItemsHandler = { (activity, success, items, error) in 
     guard success else { 
      if let error = error { 
       print(error.localizedDescription) 
      } 
      return 
     } 

      // do something if needed 
     } 
    } 
} 
// MARK: - Activity Controller Items 

/** 
ActivityControllerItems 
*/ 
private final class ActivityControllerItems: NSObject { 

    // MARK: - Properties 

    /// App name 
    fileprivate let appName = Bundle.main.infoDictionary?["CFBundleName"] as? String ?? "-" 

    /// App store web url 
    fileprivate let appStoreURL: String 

    // MARK: - Init 

    /// Init 
    fileprivate init(appStoreURL: String) { 
     self.appStoreURL = appStoreURL 
     super.init() 
    } 
} 

// MARK: - UIActivityItemSource 

/// UIActivityItemSource 
extension ActivityControllerItems: UIActivityItemSource { 

    /// Getting data items 

    /// Placeholder item 
    func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any { 
     return "" 
    } 

    /// Item for actity type 
    func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivityType) -> Any? { 
     return URL(string: appStoreURL) ?? appName 
    } 

    /// Provide info about data items 

    /// Subject field for services such as email 
    func activityViewController(_ activityViewController: UIActivityViewController, subjectForActivityType activityType: UIActivityType?) -> String { 
     return appName 
    } 
} 

共有ボタンが押されたときよりも、あなたはそれが共有サービスに依存して、画像とappStoreURLはどこにでも表示されませんことを念頭に置いてそう

ShareMenu.open(
    text: "Can you beat my score?", 
    image: UIImage(...), // set to nil if unused 
    appStoreURL: "your iTunes app store URL", // set to nil if unused 
    from: view?.window?.rootViewController 
) 

熊のようにそれを呼び出すことができます。

また、これは私がSLComposeViewController関連のコードにはなりません

+0

これはうまくいくかもしれない。 – Whirlwind

+0

ありがとう、私はUIActivityControllersが共有のために行く方法だと思います。あなたはまた、1つのボタンが必要です。私はまた、APIの共有が最終的に廃止され、どこかで完全に間違っているかもしれないと読んでいると思います。 – crashoverride777

+0

私はUIActivityControllersを調べたことはありませんでしたが、今は絶対になります。ありがとうございますこれはトンをクリアします – Matt

0

が、これはのように、通知を使用して行うことができるものを維持するために、実際に

if SLComposeViewController.isAvailable(forServiceType: SLServiceTypeFacebook) { 
    let fShare = SLComposeViewController(forServiceType: SLServiceTypeFacebook) 
    self.presentViewController(fShare!, animated: true, completion: nil) 
} 

:その方法では、あなたのコードを呼び出す必要がありますthis answer、または委任することができます。

myMethod()というメソッドを定義するMyDelegateプロトコルを宣言する必要があります。

protocol MyDelegate:class { 

     func myMethod() 
    } 

このメソッドは、このプロトタイプに準拠するすべてのクラスが実装する必要がある要件です。この例では

、あなたは労働者、およびボスとしてビューコントローラとしてシーンを見ることができます。シーンが終了すると、その上司に仕事の完了についての責任を委任するので、上司は次のものを決定することができます。私は言うことができます: "シーンは上司であり、従業員、ビューコントローラに責任を委任します..."しかし、あなたが上司として考える人は本当に問題ではありません... delegation patternは重要です。

ので、ビューコントローラは、このプロトコルに準拠している必要があり、それがmyMethod()(それは後でシーンによって呼び出されます)を実装します:

class GameViewController: UIViewController, MyDelegate { 

override func viewDidLoad() { 
    super.viewDidLoad() 

    //MARK: Conforming to MyDelegate protocol 

    if let view = self.view as! SKView? { 
     // Load the SKScene from 'GameScene.sks' 
     if let scene = GameScene(fileNamed: "GameScene") { 
      // Set the scale mode to scale to fit the window 
      scene.scaleMode = .aspectFill 

      scene.myDelegate = self 

      // Present the scene 
      view.presentScene(scene) 
     } 
    } 
    } 

func myMethod(){ 
    print("Do your stuff here") 
} 


} 

そして、ここがどこGameSceneからのコードです通知オーバー委任を選択し、その逆this articleを見て(または単に検索を取る際に調べるには

import SpriteKit 

class GameScene: SKScene { 


    weak var myDelegate:MyDelegate? 



override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { 


    self.myDelegate?.myMethod() 

    } 
} 

:私たちは私たちのビューコントローラとの通信に使用myDelegateプロパティを定義しますそう、それについていくつか素敵な記事があります)。

+0

ありがとうございます、これは分かります。それよりもはるかに多く。 – Matt

関連する問題