2016-05-20 9 views
0

私は解析の配列を照会し、データをカードのデッキに表示するようなTinderのようなアプリケーションを作成しています。配列を照会するメソッドがあり、同じメソッドで返されたリストを使用します。しかし、データのダウンロードが完了する前にバックカードが呼び出されるため、エラーが発生します。 「致命的なエラー:予期せずにオプションの値をアンラップしながら、nilを見つけ、」コードを検索するクエリを待っているので、私はこれを処理するにはどうすればよいSwift:解析クエリの待ち時間を処理する方法

を?

おかげ

import UIKit 
import MDCSwipeToChoose 

class ChoosePersonViewController: UIViewController, MDCSwipeToChooseDelegate { 

var people:[Person] = [] 
let ChoosePersonButtonHorizontalPadding:CGFloat = 80.0 
let ChoosePersonButtonVerticalPadding:CGFloat = 20.0 
var currentPerson:Person! 
var frontCardView:ChoosePersonView! 
var backCardView:ChoosePersonView! 
let nameData = "" 

required init?(coder aDecoder: NSCoder) { 
    super.init(coder: aDecoder) 
    let userObjectID = PFUser.currentUser()!.objectId! 
    let query = PFQuery(className:"Restaurants") 
    query.whereKey("Pointer", equalTo: userObjectID) 
    query.findObjectsInBackgroundWithBlock { 
     (objects: [PFObject]?, error: NSError?) -> Void in 
     if error == nil { 
      // The find succeeded. 
      print("Successfully retrieved \(objects!.count) scores.") 
      // Do something with the found objects 
      if let objects = objects { 
       for object in objects { 
        var nameData = object.objectForKey("Name") as? String 
        var imageData = object.objectForKey("Image") as? PFFile 
        imageData!.getDataInBackgroundWithBlock { (imageData, error) -> Void in 
         if error == nil { 
          if let imageData = imageData 
          { 
           let image = UIImage(data: imageData) 
           self.people.append(Person(name: nameData, image: image, age: 21, sharedFriends: 3, sharedInterest: 4, photos: 5)) 
           print(self.people) 
          } 
         } 
        } 
       } 
      } 
     } else { 
      // Log details of the failure 
      print("Error: \(error!) \(error!.userInfo)") 
     } 
    } 
} 
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { 
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 
    // Here you can init your properties 
    let imageData: PFFile 

} 

override func viewDidLoad(){ 
    super.viewDidLoad() 
    // Display the first ChoosePersonView in front. Users can swipe to indicate 
    // whether they like or dislike the person displayed. 
    self.setMyFrontCardView(self.popPersonViewWithFrame(frontCardViewFrame())!) 
    self.view.addSubview(self.frontCardView) 

    // Display the second ChoosePersonView in back. This view controller uses 
    // the MDCSwipeToChooseDelegate protocol methods to update the front and 
    // back views after each user swipe. 
    self.backCardView = self.popPersonViewWithFrame(backCardViewFrame())! 
    self.view.insertSubview(self.backCardView, belowSubview: self.frontCardView) 

    // Add buttons to programmatically swipe the view left or right. 
    // See the `nopeFrontCardView` and `likeFrontCardView` methods. 
    constructNopeButton() 
    constructLikedButton() 
} 

func suportedInterfaceOrientations() -> UIInterfaceOrientationMask{ 
    return UIInterfaceOrientationMask.Portrait 
} 

// This is called when a user didn't fully swipe left or right. 
func viewDidCancelSwipe(view: UIView) -> Void{ 

    print("You couldn't decide on \(self.currentPerson.Name)"); 
} 

// This is called then a user swipes the view fully left or right. 
func view(view: UIView, wasChosenWithDirection: MDCSwipeDirection) -> Void{ 

    // MDCSwipeToChooseView shows "NOPE" on swipes to the left, 
    // and "LIKED" on swipes to the right. 
    if(wasChosenWithDirection == MDCSwipeDirection.Left){ 
     print("You noped: \(self.currentPerson.Name)") 
    } 
    else{ 

     print("You liked: \(self.currentPerson.Name)") 
    } 

    // MDCSwipeToChooseView removes the view from the view hierarchy 
    // after it is swiped (this behavior can be customized via the 
    // MDCSwipeOptions class). Since the front card view is gone, we 
    // move the back card to the front, and create a new back card. 
    if(self.backCardView != nil){ 
     self.setMyFrontCardView(self.backCardView) 
    } 

    backCardView = self.popPersonViewWithFrame(self.backCardViewFrame()) 
    //if(true){ 
    // Fade the back card into view. 
    if(backCardView != nil){ 
     self.backCardView.alpha = 0.0 
     self.view.insertSubview(self.backCardView, belowSubview: self.frontCardView) 
     UIView.animateWithDuration(0.5, delay: 0.0, options: .CurveEaseInOut, animations: { 
      self.backCardView.alpha = 1.0 
      },completion:nil) 
    } 
} 
func setMyFrontCardView(frontCardView:ChoosePersonView) -> Void{ 

    // Keep track of the person currently being chosen. 
    // Quick and dirty, just for the purposes of this sample app. 
    self.frontCardView = frontCardView 
    self.currentPerson = frontCardView.person 
} 

func popPersonViewWithFrame(frame:CGRect) -> ChoosePersonView?{ 
    if(self.people.count == 0){ 
     return nil; 
    } 

    // UIView+MDCSwipeToChoose and MDCSwipeToChooseView are heavily customizable. 
    // Each take an "options" argument. Here, we specify the view controller as 
    // a delegate, and provide a custom callback that moves the back card view 
    // based on how far the user has panned the front card view. 
    let options:MDCSwipeToChooseViewOptions = MDCSwipeToChooseViewOptions() 
    options.delegate = self 
    //options.threshold = 160.0 
    options.onPan = { state -> Void in 
     if(self.backCardView != nil){ 
      let frame:CGRect = self.frontCardViewFrame() 
      self.backCardView.frame = CGRectMake(frame.origin.x, frame.origin.y-(state.thresholdRatio * 10.0), CGRectGetWidth(frame), CGRectGetHeight(frame)) 
     } 
    } 

    // Create a personView with the top person in the people array, then pop 
    // that person off the stack. 

    let personView:ChoosePersonView = ChoosePersonView(frame: frame, person: self.people[0], options: options) 
    self.people.removeAtIndex(0) 
    return personView 

} 
+0

どのラインが正しく失敗するのですか?なぜ画像が読み込まれるようなビューを追加していますか?イメージのロード順序を保証することはできません。 – Wain

+0

失敗する行は "self.backCardView = self.popPersonViewWithFrame(self.backCardViewFrame())!"です。どのようにビューを追加する必要がありますか? – Alexyesiam

答えて

0

私はハードループ内のすべての画像のダウンロードを開始すると、無効とネットワークの洪水や、複数の要求のタイムアウトにつながる可能性があることを示唆しています。

だけ返されたオブジェクトの全てを記憶し、最初の(そしておそらく秒)の画像を要求することを検討してください。

はすぐに返されたアイテムを保存した後のビューを追加し、それが利用可能になったときにビューに画像を追加することで対処します。

その関数が何をするか明確ではない、それがどのオブジェクトにアクセスすることを望んでいるより多くのように、それは何かかもしれませんが、あなたの問題は、実際に、まだ存在していないビューを削除しようとしているに関連するかもしれないと思われます次のイメージがダウンロードされていないので、配列にまだ追加されていません。したがって、返す適切なアイテムを見つける/作成できません。イメージとビューの使用方法を変更すると、これらの原因のいずれかが解決されます。

+0

私はそれをコード化する方法を概念化するのに苦労しています。あなたは正しい方向に私を押し込めますか?オブジェクトは非同期であるので、私はブロック自体内のほかのビューをロードするために他にどこかわからないそう、私はでエラーが出ます「self.setMyFrontCardView(self.popPersonViewWithFrame(self.frontCardViewFrame())!)」 – Alexyesiam

+0

あなたが必要でほとんどの2つのビューと2つの画像、現在の画像と次の画像が同時に表示されます。技術的には、画像がまだ準備されていなくても、ビューは存在する可能性があります。したがって、最初の2つのビューをただちに作成してください。トランジションアニメーションが終了すると、他のビューが作成されます(最初のビューが不要になった場合は破棄し、アニメーション化する準備ができている画面をオフにする)。 – Wain

+0

コードを更新しました。私はあなたが示唆したようにイメージが読み込まれる前にカードビューを作成しようとしていますが、それは存在する人の配列に依存しているようです。 "self.setMyFrontCardView(self.popPersonViewWithFrame(self.frontCardViewFrame())!"でエラーが発生します) " – Alexyesiam

関連する問題