2017-03-27 5 views
3

나는 Xcode에서 스프라이트 키트와 장면을 사용하여 게임을 개발했습니다. 이제 나는 트위터와 페이스 북에 높은 점수를 게시하는 기능을 통합하려고합니다. 주변을 둘러 보았고 대부분의 사람들은 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 관련 코드에 가지 않을거야 도움이 텍스트에 예컨대

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

희망을 추가합니다. 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:) 방법.내가 위임에 대한 또 다른 예를 작성합니다 청소 : 내가 말했듯이

2

다른 UIViewController에서 UIViewController를 표시해야하기 때문에이 오류가 발생합니다. 자기 (SKScene)는 UIViewController에 없기 때문에 그래서

self.presentViewController(...) 

이 작동하지 않습니다. 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 
    } 
} 

공유 버튼을 누를 때보다 당신은 그것을 공유 서비스에 따라, 이미지와 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 
) 

곰처럼 호출 할 수 있습니다.

또한 현장에서 점수 값을 사용할 수 있으며,이

+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에서 코드 어디 우리는 우리의 뷰 컨트롤러와 통신하는 데 사용하는 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