2017-03-27 65 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

請發佈您正在使用的代碼(相關部分)。但通常,您可以在適當的視圖控制器中指定視圖控制器相關的方法,並在您想要調用這些方法時從場景發佈通知。 – Whirlwind

+0

來自'else if'塊的代碼應該替換爲可以發佈通知的代碼。它也應該被移動到一個合適的視圖控制器,該視圖控制器有一個必需的成員方法並監聽所提到的通知。 – Whirlwind

+0

我不確定我是否遵循,我將代碼移到了自定義視圖控制器類,但是我仍然無法從我的場景中調用它。 – Matt

回答

1

我不會進入SLComposeViewController相關的代碼。除了crashoverride777提出的方法之外,我只會向您展示兩種技術。因此,第一種技術是使用通知,像這樣:

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:)方法。在這種方法中,你應該打電話給你的代碼:

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

事實上,我會寫的代表團另一個例子,保持乾淨的東西:)

2

,因爲你需要從其他的UIViewController提出一個UIViewController您收到此錯誤。所以

self.presentViewController(...) 

不會工作,因爲自我(SKScene)不是UIViewController。從SKScene介紹,你會不得不說這

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

我建議你不要使用那些API了。更好地使用UIActivityViewController來滿足您的共享需求。這樣,您只需在應用程序中使用一個共享按鈕,即可共享各種服務(電子郵件,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 
    } 
} 

當按下分享按鈕比你可以把它像這樣

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 
) 

記住,圖像和appStoreURL不會出現遍地開花,這取決於共享服務。

您也可以從場景中使用你的分數值,並將它添加到文本e.g

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

希望這有助於

+0

是的,這也可能工作。 – Whirlwind

+0

謝謝,我認爲UIActivityControllers是共享的方式。你也只需要1個按鈕。我也相信在某個地方看到那些共享API的人最終會被棄用,在這裏我可能會完全錯誤。 – crashoverride777

+0

我從來沒有探索UIActivityControllers,但現在絕對會。謝謝你們,這明白了一大堆 – Matt

0

正如我所說的,這是可以使用的通知完成,像this answer,或者您可以與委託一起去:

首先,您應該聲明MyDelegate協議,該協議定義了一種名爲myMethod()的方法。

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代碼,你定義myDelegate的性質,我們用我們的視圖控制器進行通信:

import SpriteKit 

class GameScene: SKScene { 


    weak var myDelegate:MyDelegate? 



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


    self.myDelegate?.myMethod() 

    } 
} 

要了解當選擇了通知和代表團反之亦然看看this article(或只是搜索所以,有一些關於此的好帖子)。

+0

謝謝,這確實有道理。比它做得更多。 – Matt