今回は出会いをサポートするアプリを開発していきます。
Facebookログインでユーザ登録をし、好みの相手を見つけます。Tinder風のUIで相手を選ぶ事ができ、好みにした相手にメールでメッセージを送る機能を実装していきます。

Xcodeプロジェクト作成
Deai
でXcodeプロジェクトを新規作成してください。
使用するテンプレートはSingle View Application
となります。

入力項目 |
入力値 |
Product Name |
Deai |
Team |
None |
Oganization Name |
任意(”ALJ”など自分が所属している組織の名前を入れる) |
Oganization Identifier |
jp.co.al-j |
Language |
Swift |
Devices |
iPhone |
Use Core Data |
チェックを外す |
include Unit Tests |
チェックを外す |
include UI Tests |
チェックを外す |
Cocoapods設定
プロジェクトフォルダをターミナルにドラッグします。

ターミナルの画面でpod init
を実行します。
これでPodfile
がプロジェクト内に作成されますので、open
コマンドで開きましょう。
テキストエディタが開いてPodfile
を編集できますので、下記内容になるように修正し、保存してください。
Podfile
platform :ios, '9.0' use_frameworks! target 'Deai' do pod 'NCMB', :git => 'https://github.com/NIFTYCloud-mbaas/ncmb_ios.git' end
|
ターミナルに戻り下記コマンドでNCMBのライブラリをダウンロードします。
このように表示されればOKです。

一度Xcodeプロジェクトを閉じて、下図のとおりxcworkspace
からXcodeを開き直してください。

NCMB初期設定
次に、NCMBの初期設定をおこないます。
NCMBはObjective-Cという言語で作られており、Swiftで利用する為には、Objective-CからSwiftへ橋渡しする為のファイル(Bridging-Header.h)を作成し、Swiftで扱えるように設定する必要があります。
まずは橋渡しする為のファイル(Bridging-Header.h)を作成しましょう。
プロジェクトの「Deai」フォルダーで右クリックをし、「New Files..」を選択します。

「Header File」を選択し、「Next」を押します。

Save Asに「Deai-Bridging-Header.h」と入力して「Create」ボタンを押します。

「Deai-Bridging-Header.h」を以下へ編集します。
Deai-Bridging-Header.h

Xcodeへ「Deai-Bridging-Header.h」を読み込ませる為の設定をします。
「Deai」プロジェクトの「Build Settings」の「Objective-C Bridging Header」に「Deai/Deai-Bridging-Header.h」を指定します。

Facebookログイン実装準備
次にFacebookログイン機能を実装するための準備をします。Facebookログインの機能を利用するためにはFacebookが提供しているFacebook Developers
サイトでアプリ登録をし、SDKをダウンロードしてプロジェクトに取り込む必要があります。
Facebook Developers
サイトにアクセスしてください。
https://developers.facebook.com/
Facebookにログインしていない場合にはログインし、下図のように新しいアプリを追加
をクリックします。

表示名、連絡先メールアドレス、カテゴリを選択し、「アプリIDを作成してください」を選択します。
※表示名はios-deai
、カテゴリはコミュニケーション
を選択します。メールアドレスはご自身のメールアドレスを入力します。

セキュリティチェックで表示されている文字列を入力して「送信」を押します。

次にDownload SDK
をダウンロードします。以下のドキュメントボタンをクリックします。

IOS SDK
を選択します。

Download the SDK
を選択し、ダウンロードします。

ダウンロードが完了したらzipファイルを解凍し、下図のように下記のframeworkをXcodeプロジェクトのFrameworks
グループの中にドラッグしてください。
- Bolts.framework
- FacebookSDKStrings.framework
- FBAudienceNetwork.framework
- FBSDKCoreKit.framework
- FBSDKLoginKit.framework
- FBSDKMessengerShareKit.framework
- FBSDKShareKit.framework



Facebook Developers
にBundle Identifier
を設定します。
XcodeのBundle Identifier
をコピーします。

Facebook Developers
サイトの設定画面を開きます。そしてプラットフォームを追加
を押します。

iOSを選択し、バンドルID
を設定します。そして、変更を保存
を押します。


次に、Xcodeプロジェクトのinfo.plist
ファイルを編集していきます。
下図のようにinfo.plist
で右クリックし、Open As -> Source Code
をクリックします。
そうすると、info.plist
の中身であるXML形式のファイルがエディタエリアに表示されます。

info.plist
へ以下を追加します
<key>UISupportedInterfaceOrientations</key> <array> <string>UIInterfaceOrientationPortrait</string> </array> <!-- 追加(ここから) --> <key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>fb{your-app-id}</string> </array> </dict> </array> <key>FacebookAppID</key> <string>{your-app-id}</string> <key>FacebookDisplayName</key> <string>ios-deai</string> <key>LSApplicationQueriesSchemes</key> <array> <string>fbapi</string> <string>fb-messenger-api</string> <string>fbauth2</string> <string>fbshareextension</string> </array> <key>NSPhotoLibraryUsageDescription</key> <string>PhotoLibrary</string> <!-- 追加(ここまで) --> </dict> </plist>
|
※「{your-app-id}」はアプリIDを設定してください。

アプリレビュー
のメニューを選択し、以下の箇所のスイッチをクリックしてON
にします。

「アプリを公開しますか?」というダイアログが表示されますので確認
ボタンをクリックします。

これでFacebook Developersのアプリ登録設定は完了です。
NCMB利用準備
今回もNCMB(Nifty Mobile Backend)を利用していきます。
Deai
でアプリ登録しておいてください。

http://mb.cloud.nifty.com/
表示されたアプリケーションキー
、クライアントキー
は保存しておいてください。

FacebookSDKとNCMBを利用するためのコードを追加していきます。
まずはAppDelegate
を開き下記のようにコードを追加してください。
AppDelegate.swift
import UIKit
import NCMB import FBSDKCoreKit
@UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { NCMB.setApplicationKey("【アプリケーションキー】", clientKey: "【クライアントキー】") FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions) return true } : : : func applicationDidBecomeActive(application: UIApplication) { FBSDKAppEvents.activateApp() } : : func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool { return FBSDKApplicationDelegate.sharedInstance().application(application, openURL: url, sourceApplication: sourceApplication, annotation: annotation) } }
|
このコードを追加する事によりFacebookSDKとNCMBを使う準備が整いました。
画面レイアウト
設定画面
Main.storyboard
で画面レイアウトを構築していきます。
まずはNavigationController
を追加します。
メニューバーからEditer -> Embed in -> NavigationController
を選択してください。

このようにNavigationController
が追加されます。

ViewControllerはImageView
とSwitch
とButton
とLabel
とBar Button Item
を下図のように配置してください。

IBOutlet
も下図のように関連付けておいてください。

Facebookログイン画面
Facebookログイン画面をレイアウトしていきます。新しくViewControllerを追加し、下図のように青いButton
を配置してFacebookログイン
というラベルを入力してください。

Segue(Show)
で追加したViewControllerと接続し、Identifier
をtoLogin
にします。

FBLoginViewController.swift
を新しく作成してMain.storyboardに追加したViewControllerと関連付けてください。

FBログイン機能実装
まずViewController.swift
にてNCMBログインチェックをする処理を追加し、未ログインだった場合にはFBLoginViewController
に遷移するようにします。
ViewController.swift
import UIKit
import NCMB
class SettingViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView! @IBOutlet weak var interestedInWomen: UISwitch! override func viewDidLoad() { super.viewDidLoad() } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) ncmbLoginCheck() } func ncmbLoginCheck(){ if (NCMBUser.current() != nil) { print("ログイン済み") } else { print("未ログイン") self.performSegue(withIdentifier: "toLogin", sender: nil) } } : : }
|
次はFBLoginViewController.swiftにてFBログイン機能を追加します。
FBLoginViewController.swift
import UIKit
import NCMB import FBSDKCoreKit import FBSDKLoginKit
class ViewController: UIViewController { : : : @IBAction func loginFacebookAction(sender: AnyObject) { let fbLoginManager : FBSDKLoginManager = FBSDKLoginManager() fbLoginManager.logIn(withReadPermissions: ["email"], from: self) { (result, error) -> Void in if (error == nil){ print("FBログイン成功") let fbloginresult : FBSDKLoginManagerLoginResult = result! if(fbloginresult.grantedPermissions.contains("email")){ self.returnUserData() } } else { print("FBログイン失敗:\(error)") } } } func returnUserData() { let graphRequest:FBSDKGraphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id,email,gender,link,locale,name,timezone,updated_time,verified,last_name,first_name,middle_name"]) graphRequest.start(completionHandler: { (connection, result, error) -> Void in if ((error) != nil) { print("FBユーザ情報取得失敗: \(error)") }else{ print("FBユーザ情報取得成功: \(result)") self.ncmbLogin(result: result as AnyObject) } }) } : : }
|
ボタンタップ時にFacebookログインSDKのFBSDKLoginManager
を利用してFacebookログインを試行します。ユーザがFBのログインを成功させると、ユーザ情報を取得するreturnUserData
メソッドにてFacebookに登録してあるログインしたユーザの情報(メールアドレスや名前、性別)を取得します。
NCMBログイン・ユーザ登録
次にFacebookログインで取得したユーザ情報を使ってNCMBにログイン、またはユーザ登録する処理を追加します。
まずNCMBにログインを試行し、ログイン失敗した場合にはユーザ登録をする流れを追加します。
func ncmbLogin(result:AnyObject){ let userId = result.valueForKey("id") as! String let ud = NSUserDefaults.standardUserDefaults() var password = "" if let passwd = ud.objectForKey("password") { password = passwd as! String } else { password = NSUUID().UUIDString ud.setObject(password, forKey: "password") } NCMBUser.logInWithUsernameInBackground(userId, password: password, block:({(user, error) in if (error != nil){ print("ログイン失敗:\(error)") self.ncmbUserRegister(result,password: password) }else{ print("ログイン成功:\(user)") self.navigationController?.popToRootViewControllerAnimated(true) } })) }
func ncmbUserRegister(result:AnyObject,password:String) { let user = NCMBUser() user.userName = result.valueForKey("id") as! String user.password = password user.mailAddress = result.valueForKey("email") as! String user.setObject(result.valueForKey("gender") as! String, forKey: "gender") user.setObject(result.valueForKey("name") as! String, forKey: "fullname") let acl = NCMBACL() acl.setPublicReadAccess(true) acl.setPublicWriteAccess(true) user.ACL = acl user.signUpInBackgroundWithBlock({(error) in if (error != nil){ print("ユーザ登録失敗:\(error)") }else{ print("ユーザ登録完了:\(user)") self.navigationController?.popToRootViewControllerAnimated(true) } }) }
|
その後にNCMBに既に登録されているユーザかのチェックを実施し、未ログインの場合にはユーザ登録の処理ncmbUserRegister
メソッドを呼び出してNCMBにユーザ登録しています。
ユーザプロフィール画像表示・利用設定
FBログインでユーザ情報を取得できましたので、それを使って画面にユーザのプロフィール画像を表示させます。またスイッチで出会いたい性別を選択してそれをNCMBに保存する処理も追加します。
ViewController.swift
func ncmbLoginCheck(){ if (NCMBUser.currentUser() != nil) { print("ログイン済み") self.setMyPicture() } else { print("未ログイン") self.performSegueWithIdentifier("toLogin", sender: nil) } } : :
func setMyPicture(){ let user = NCMBUser.currentUser() print("user:\(user)") let fbPictureUrl = "https://graph.facebook.com/" + user.userName + "/picture?type=large" if let fbpicUrl = NSURL(string: fbPictureUrl) { if let data = NSData(contentsOfURL: fbpicUrl) { self.imageView.image = UIImage(data: data) } } }
@IBAction func logoutButtonTapped(sender: AnyObject) { NCMBUser.logOut() ncmbLoginCheck() }
|
Main.storyboardを開いてFacebookログインボタンのIBAction
を関連付けします。

この状態で一度Runして動作確認してみましょう。Facebookログイン画面が表示してログインすると、ViewController画面に自分のプロフィール画像が表示されていればOKです。



デバッグエリアにもFacebookログイン成功時にユーザ情報が取得できている事を確認してください。

またNCMB管理画面へ遷移し、ユーザ登録されている事も確認してください。

テストユーザ作成
今回は出会いアプリなので、異性のユーザを予め登録しないといけません。
NCMB管理画面でテストユーザを作成しておきます。
下図のようにNCMB管理画面で新しい会員
ボタンをクリックするとレコードが1行追加されます。


userName
とpassword
を設定するとユーザが追加されます。

user1
〜user5
まで作成してください。

また性別は今回は異性は女性にしますのでgender
の項目はfemale
にしてください。またmainAddress
、fullname
も下図のように入れてください。

最後に作成したユーザのパーミッションを変更します。
下記の部分をクリックしてパーミッションを全員
、読み込み可、書き込み可
にしてください。


TinderUI画面作成
次に下図のように異性のプロフィール画像が表示され、Tinder風に画面をフリックすると、好み、好みじゃないのを選別できるようにします。

画面レイアウト
Main.storyboardを開いて下図のように新しくViewControllerを追加してください。

Main.storyboardを開き新しくViewControllerを追加して、設定画面とSegue(Show)
で接続します。identifierはtoTinder
にしてください。


TinderViewController.swift
のファイルを作成して関連付けしてください。

Navigation item
を追加してタイトルをお相手確認
としておきます。

下図のようにImageView
、Label
、Bar Button Item
を配置して画面レイアウトしてください。

IBOutLet
、IBAction
で関連付けしてください。

好みの性別を選択
次に、好みの性別を選択してNCMBのログインユーザの情報を更新する処理を追加します。
ViewController.swift
@IBAction func startButtonTapped(sender: AnyObject) { let user = NCMBUser.currentUser() user.setObject(interestedInWomen.on, forKey: "interestedInWomen") user.saveEventually({(NSError error) in if (error != nil) { print("保存失敗:\(error)") }else{ print("保存成功:\(user)") self.performSegueWithIdentifier("toTinder", sender: nil) } }) }
|
Main.storyboardを開いて下図のとおりIBAction
を関連付けします。

TinderUI実装
それではTinderUIを実装していきます。
まず画面表示時の処理を追加します。次の機能を追加していきます。
この画面ではログインユーザの現在地を取得し、NCMBのユーザ情報として保存します。
その現在地から近いユーザを検索してそのユーザのプロフィール画像を画面に表示させます。
画面表示時
- ドラッグ操作検知設定
- 現在地を取得してNCMBに保存
- ユーザ取得(探している性別で、現在地から近いユーザを1件取得)
- プロフィール画像を表示
ドラッグ検知設定と、現在地を取得してNCMBに保存する処理を追加します。
TinderViewController.swift
import UIKit //////////////// ▼▼ 追加 ▼▼ //////////////// import CoreLocation import NCMB //////////////// ▲▲ 追加 ▲▲ //////////////// class TinderViewController: UIViewController { @IBOutlet weak var userImageView: UIImageView! //////////////// ▼▼ 追加 ▼▼ //////////////// let locationManager = CLLocationManager() var displayedUser = NCMBUser() // 表示しているユーザのID //////////////// ▲▲ 追加 ▲▲ //////////////// override func viewDidLoad() { super.viewDidLoad() //////////////// ▼▼ 追加 ▼▼ //////////////// // 画像にドラッグ認識 let gesture = UIPanGestureRecognizer(target: self, action: Selector("wasDragged:")) userImageView.addGestureRecognizer(gesture) userImageView.userInteractionEnabled = true // 現在値取得 self.getCurrentLocationAndDbSave() //////////////// ▲▲ 追加 ▲▲ //////////////// } : : : //////////////// ▼▼ 追加 ▼▼ //////////////// //-------------------------------------- // 現在地を取得してDB保存 //-------------------------------------- func getCurrentLocationAndDbSave(){ // 位置情報取得 // 承認されていない場合はここで認証ダイアログを表示 let status = CLLocationManager.authorizationStatus() if(status == CLAuthorizationStatus.NotDetermined) { print("didChangeAuthorizationStatus:\(status)"); self.locationManager.requestAlwaysAuthorization() } NCMBGeoPoint.geoPointForCurrentLocationInBackground({(geopoint,error) in if error != nil{ print("geo point error:\(error)") } else { print("geo point success lat:\(geopoint.latitude), lon:\(geopoint.longitude)") let user = NCMBUser.currentUser() user.setObject(geopoint, forKey: "geopoint") user.saveEventually({(error) in if error != nil { print("現在地保存失敗:\(error)") } else { print("現在地保存成功:\(user)") // ユーザ取得 self.fetchUser() } }) } }) } //////////////// ▲▲ 追加 ▲▲ //////////////// : : }
|
現在地を取得するためにはinfo.plist
ファイルに下記の内容を追加する必要があります。
下図のようにinfo.plist
で右クリックし、Open As -> Source Code
をクリックします。
そうすると、info.plist
の中身であるXML形式のファイルがエディタエリアに表示されます。

XML形式の中身が表示されたら下記内容を追加してください。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> : : <array> <string>UIInterfaceOrientationPortrait</string> <string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeRight</string> </array> //////////////// ▼▼ 追加 ▼▼ //////////////// <key>NSLocationAlwaysUsageDescription</key> <string>I always need location</string> <key>NSLocationWhenInUseUsageDescription</key> <string>I need location when app in use</string> //////////////// ▲▲ 追加 ▲▲ //////////////// </dict> </plist>
|
またプロジェクトエディタのCapabilities
のBackground Modes
をOn
にしLocation updates
のチェックボックスを有効にしてください。

この状態で一度実機でRunして動作確認しておいきましょう。
問題なければデバッグエリアに緯度・経度の値が表示されます。
緯度・経度を取得するには実機での確認が必要になります。
一度Runしてみましょう。下図のようにデバッグエリアに現在地保存成功
が表示されればOKです。

現在地の緯度・経度の情報がNCMBのユーザに追加されている事も確認しましょう。

今後ユーザ検索の際に他のユーザにも緯度・経度の情報を入れていないといけないので、先程追加したユーザにも緯度・経度の情報をいれておいてください。
(コピー・アンド・ペーストで問題ありません。)


ユーザ取得
それでは好みの相手を探すためのユーザ取得の処理を追加していきます。
- ユーザ取得(探している性別で、現在地から近いユーザを1件取得)
- プロフィール画像を表示
//////////////// ▼▼ 追加 ▼▼ //////////////// //-------------------------------------- // 現在地を取得してDB保存 //-------------------------------------- func getCurrentLocationAndDbSave(){ : : : NCMBGeoPoint.geoPointForCurrentLocationInBackground({(geopoint,error) in if error != nil{ print("geo point error:\(error)") } else { print("geo point success lat:\(geopoint.latitude), lon:\(geopoint.longitude)") let user = NCMBUser.currentUser() user.setObject(geopoint, forKey: "geopoint") user.saveEventually({(error) in if error != nil { print("現在地保存失敗:\(error)") } else { print("現在地保存成功:\(user)") //////////////// ▼▼ 追加 ▼▼ //////////////// // ユーザ取得 self.fetchUser() //////////////// ▲▲ 追加 ▲▲ //////////////// } }) } }) }
//-------------------------------------- // ユーザ取得 //-------------------------------------- func fetchUser(){ //-------------------------------------- // 現在地に近いユーザ検索 //-------------------------------------- // ログインユーザの現在地取得 let currentGeoPoint = NCMBUser.currentUser().objectForKey("geopoint") as! NCMBGeoPoint // 探している性別 let interestedInWomen = NCMBUser.currentUser().objectForKey("interestedInWomen") as! Bool // クエリ作成 let query = NCMBQuery(className: "user") query.whereKey("geopoint", nearGeoPoint:currentGeoPoint, withinKilometers: 1.0) // 探している性別に合わせ検索条件変更 if interestedInWomen == true { query.whereKey("gender", equalTo: "female") } else { query.whereKey("gender", equalTo: "male") } // 取得件数は1件 query.limit = 1 query.findObjectsInBackgroundWithBlock({(NSArray objects, NSError error) in if (error != nil){ print("友達取得失敗:\(error)") } else { print("友達取得成功:\(objects)") if objects.count > 0 { self.displayedUser = objects[0] as! NCMBUser // ユーザプロフィール画像表示 let fbPictureUrl = "https://dl.dropboxusercontent.com/u/6866756/swift/deai/" + objects[0].userName + ".png" // 本番環境は下記 // let fbPictureUrl = "https://graph.facebook.com/" + objects[0].userName + "/picture?type=large" if let fbpicUrl = NSURL(string: fbPictureUrl) { if let data = NSData(contentsOfURL: fbpicUrl) { self.userImageView.image = UIImage(data: data) } } } else { // 画像を初期化して非表示 self.userImageView.image = UIImage() self.userImageView.userInteractionEnabled = false } } }) } //////////////// ▲▲ 追加 ▲▲ ////////////////
|
この状態で一度Runして確認してみましょう。他のユーザのプロフィール画像が表示されればOKです。

ドラッグしたら画像が移動
次に、表示されたプロフィール画像をドラッグしたらドラッグした場所に追随して移動する処理を追加します。
TinderViewController.swift
//-------------------------------------- // ドラッグ検知 //-------------------------------------- func wasDragged(gesture: UIPanGestureRecognizer) { // ドラッグ度合取得 let translation = gesture.translationInView(self.view) // ドラッグ対象View取得 let imageView = gesture.view! // Viewを移動 imageView.center = CGPoint( x: self.view.bounds.width / 2 + translation.x, y: self.view.bounds.height / 2 + translation.y ) // 中央からのX軸移動量取得 let xFromCenter = imageView.center.x - self.view.bounds.width / 2 // X軸移動量から縮小率算出 let scale = min(100 / abs(xFromCenter), 1) // X軸移動量から回転率算出 var rotation = CGAffineTransformMakeRotation(xFromCenter / 200) // 回転・縮小の値をセット var stretch = CGAffineTransformScale(rotation, scale, scale) // Viewを回転・縮小 imageView.transform = stretch // ドラッグ完了時X軸が100p以上移動していたらDB登録して次のユーザ表示 if gesture.state == UIGestureRecognizerState.Ended { var acceptedOrRejected = "" if imageView.center.x < 100 { acceptedOrRejected = "rejected" } else if imageView.center.x > self.view.bounds.width - 100 { acceptedOrRejected = "accepted" } print("好みの相手判断:\(acceptedOrRejected)") // 元の位置に戻す rotation = CGAffineTransformMakeRotation(0) stretch = CGAffineTransformScale(rotation, 1, 1) imageView.transform = stretch imageView.center = CGPoint(x: self.view.bounds.width / 2, y: self.view.bounds.height / 2) } }
|
それではこれで一度Runしてみましょう。
下図のように登録したユーザのプロフィール画像をドラッグして移動するか確認してください。

また、ある一定ドラッグして移動するとデバッグエリアにaccepted
かrejected
が出力される事を確認してください。

好み判断処理実装
accepted
かrejected
かを判断し、その情報をNCMBに保存する処理を追加します。そして、一度「好み」か「好みじゃない」かを判断したユーザは検索対象から外して新しいユーザが検索されるようにします。
TinderViewController.swift
//-------------------------------------- // ドラッグ検知 //-------------------------------------- func wasDragged(gesture: UIPanGestureRecognizer) { : : : // ドラッグ完了時X軸が100p以上移動していたらDB登録して次のユーザ表示 if gesture.state == UIGestureRecognizerState.Ended { var acceptedOrRejected = "" if imageView.center.x < 100 { acceptedOrRejected = "rejected" } else if imageView.center.x > self.view.bounds.width - 100 { acceptedOrRejected = "accepted" } print("好みの相手判断:\(acceptedOrRejected)") //////////////// ▼▼ 追加 ▼▼ //////////////// if acceptedOrRejected != "" { // 登録処理 let action = NCMBObject(className: "Action") action.setObject(NCMBUser.currentUser(), forKey: "from") action.setObject(self.displayedUser, forKey: "to") action.setObject(acceptedOrRejected, forKey: "acceptedOrRejected") let acl = NCMBACL() acl.setPublicReadAccess(true) action.ACL = acl action.saveInBackgroundWithBlock({(error) in if error != nil{ print("Actionテーブル保存失敗:\(error)") } else { print("Actionテーブル保存成功:\(action)") self.fetchUser() } }) } //////////////// ▲▲ 追加 ▲▲ //////////////// // 元の位置に戻す rotation = CGAffineTransformMakeRotation(0) stretch = CGAffineTransformScale(rotation, 1, 1) imageView.transform = stretch imageView.center = CGPoint(x: self.view.bounds.width / 2, y: self.view.bounds.height / 2) } }
|
accepted
かrejected
かを判断したタイミングでNCMBのAction
テーブルに保存するようにして、再度ユーザ取得処理を実行するようにしています。
この状態でRunして動作確認してみましょう。ユーザ画像を右か左かにドラッグすると、デバッグエリアに下記の内容が出力されるか確認してください。

また、NCMB管理画面にアクセスしてAction
テーブルにデータが追加されている事を確認しましょう。

ユーザ取得処理をこのまま実行すると何回やっても同じユーザしか表示しませんので、一度判断したユーザは除外するようにします。ユーザ取得処理を下記に差し替えてください。
TinderViewController.swift
func fetchUser(){ let query1 = NCMBQuery(className: "Action") query1.whereKey("from", equalTo: NCMBUser.currentUser()) query1.findObjectsInBackgroundWithBlock({(NSArray objects, NSError error) in if (error != nil){ print("アクション取得失敗:\(error)") } else { print("アクション取得成功:\(objects)") let currentGeoPoint = NCMBUser.currentUser().objectForKey("geopoint") as! NCMBGeoPoint print("currentGeoPoint lat:\(currentGeoPoint.latitude), lon:\(currentGeoPoint.longitude)") let interestedInWomen = NCMBUser.currentUser().objectForKey("interestedInWomen") as! Bool let query2 = NCMBQuery(className: "user") query2.whereKey("geopoint", nearGeoPoint:currentGeoPoint, withinKilometers: 1.0) if interestedInWomen == true { query2.whereKey("gender", equalTo: "female") } else { query2.whereKey("gender", equalTo: "male") } query2.limit = 1 var ignoredUsers = [""] for object in objects { let action = object as! NCMBObject let user = action.objectForKey("to") print("to user:\(user)") ignoredUsers.append(user.objectId as String) } print("ignoredUsers:\(ignoredUsers)") query2.whereKey("objectId", notContainedInArray: ignoredUsers) query2.findObjectsInBackgroundWithBlock({(NSArray objects, NSError error) in if (error != nil){ print("友達取得失敗:\(error)") } else { print("友達取得成功:\(objects)") if objects.count > 0 { self.displayedUser = objects[0] as! NCMBUser let fbPictureUrl = "https://dl.dropboxusercontent.com/u/6866756/swift/deai/" + objects[0].userName + ".png" if let fbpicUrl = NSURL(string: fbPictureUrl) { if let data = NSData(contentsOfURL: fbpicUrl) { self.userImageView.image = UIImage(data: data) } } } else { self.userImageView.image = UIImage() self.userImageView.userInteractionEnabled = false } } }) } }) }
|
上記コードで下記の2つのクエリを実行し、好み判断したユーザを除外して検索するようにしています。
- クエリ1 Actionテーブルから既にアクションしているリストを取得
- クエリ2 現在地に近いユーザ検索(クエリ1で取得したユーザは除外)
それではこれで一度Runしてみましょう。
下図のように登録したユーザのプロフィール画像をドラッグしたら、プロフィール画像が切り替わる事を確認してください。

好みユーザ一覧画面作成
「好み」か「好みじゃない」ユーザを判断した後に「好み」のユーザに連絡できるように、好みのユーザを一覧で表示する画面を作成します。
画面レイアウト
Main.storyboardを開き新しくViewControllerを追加して、お相手確認画面とSegue(Show)
で接続します。下図の通りBar Button Item
からSegueを追加してください。

ContactViewController.swift
のファイルを作成して関連付けしてください。

Navigation item
を追加してタイトルをお好み一覧
としておきます。

下図のようにTableView
を配置してPrototype Cell
を1
にしてください。

CellのIdentifier
をCell
にしてください。

IBOutLet
で関連付けしてください。

好みユーザ一覧表示
それでは好みユーザリストをTableViewに表示させるようにします。
好みユーザはNCMBのAction
テーブルの中に格納されていて、acceptedOrRejected
がaccepted
になっているものを探しだします。
ContactViewController.swift
import UIKit //////////////// ▼▼ 追加 ▼▼ //////////////// import NCMB //////////////// ▲▲ 追加 ▲▲ ////////////////
//////////////// ▼▼ プロトコル追加 ▼▼ //////////////// class ContactViewController: UIViewController,UITableViewDataSource,UITableViewDelegate { //////////////// ▲▲ プロトコル追加 ▲▲ ////////////////
//////////////// ▼▼ 追加 ▼▼ //////////////// var objects = [NCMBObject]() //////////////// ▲▲ 追加 ▲▲ //////////////// @IBOutlet weak var tableView: UITableView! override func viewDidLoad() { super.viewDidLoad() //////////////// ▼▼ 追加 ▼▼ //////////////// tableView.delegate = self tableView.dataSource = self //////////////// ▲▲ 追加 ▲▲ //////////////// } //////////////// ▼▼ 追加 ▼▼ //////////////// override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) self.fetchUsers() } //////////////// ▲▲ 追加 ▲▲ //////////////// : : //////////////// ▼▼ 追加 ▼▼ //////////////// // お好みユーザ取得 func fetchUsers(){ let query = NCMBQuery(className: "Action") query.whereKey("from", equalTo: NCMBUser.currentUser()) query.whereKey("acceptedOrRejected", equalTo: "accepted") query.includeKey("to") query.findObjectsInBackgroundWithBlock({(NSArray objects, NSError error) in if error != nil { print("取得失敗:\(error)") } else { print("取得成功:\(objects)") self.objects = objects as! [NCMBObject] self.tableView.reloadData() } }) } //////////////// ▲▲ 追加 ▲▲ ////////////////
//////////////// ▼▼ 追加 ▼▼ //////////////// //---------------------------- // MARK: - TableView DataSource //---------------------------- func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return self.objects.count } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) let toUser = self.objects[indexPath.row].objectForKey("to") as! NCMBUser cell.textLabel!.text = toUser.userName return cell } //////////////// ▲▲ 追加 ▲▲ //////////////// }
|
この状態で確認してみましょう。好みにしたユーザIDがTableViewに表示されていればOKです。

好みユーザ詳細画面
好みユーザ一覧が表示されるようになったので、次は好みユーザのセルをタップしたときにユーザの詳細を表示し、ユーザのメールアドレス宛てにメールを送信できるようにします。
画面レイアウト
Main.storyboardを開き新しくViewControllerを追加して、お好み一覧画面とSegue(Show)
で接続します。SegueのIdentifier
はtoUserDetail
にします。

UserDetailViewController.swift
のファイルを作成して関連付けしてください。

Navigation item
を追加してタイトルをユーザ詳細
としておきます。

下図のようにImageView
、Label
、Button
を追加してください。

IBOutLet
、IBAction
で関連付けしてください。

ユーザ詳細表示
好みユーザの詳細を表示するようにします。
UserDetailViewController.swift
import UIKit //////////////// ▼▼ 追加 ▼▼ //////////////// import NCMB //////////////// ▲▲ 追加 ▲▲ //////////////// class UserDetailViewController: UIViewController{ @IBOutlet weak var mailLabel: UILabel! @IBOutlet weak var imageView: UIImageView! //////////////// ▼▼ 追加 ▼▼ //////////////// var user = NCMBUser() // 選択されたユーザ //////////////// ▲▲ 追加 ▲▲ ////////////////
override func viewDidLoad() { super.viewDidLoad() //////////////// ▼▼ 追加 ▼▼ //////////////// // メールアドレス表示 mailLabel.text = user.objectForKey("mailAddress") as? String // 画像表示 let fbPictureUrl = "https://dl.dropboxusercontent.com/u/6866756/swift/deai/" + user.userName + ".png" // 本番環境は下記 // let fbPictureUrl = "https://graph.facebook.com/" + user.userName + "/picture?type=large" if let fbpicUrl = NSURL(string: fbPictureUrl) { if let data = NSData(contentsOfURL: fbpicUrl) { self.imageView.image = UIImage(data: data) } } //////////////// ▲▲ 追加 ▲▲ //////////////// } : : }
|
また、前の画面ではTableViewのセルタップ時の処理を追加してUserDetailViewController
に画面遷移するようにします。画面遷移時に選択したユーザ情報を送るようにします。
ContactViewController.swift
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { let toUser = self.objects[indexPath.row].objectForKey("to") as! NCMBUser self.performSegueWithIdentifier("toUserDetail", sender: toUser) }
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if segue.identifier == "toUserDetail" { let vc = segue.destinationViewController as! UserDetailViewController vc.user = sender as! NCMBUser } }
|
一度Runしてみましょう。好み一覧画面からセルタップするとユーザの詳細(プロフィール画像、メールアドレス)が表示されている事を確認してください。

ユーザ連絡機能追加
最後にユーザの連絡先を追加する機能を追加していきます。
ユーザのメールアドレス宛てにメールを遅れるようにします。
メールを送るにはMessageUI.framework
のMFMailComposeViewController
を使うと簡単に実装できます。
UserDetailViewController.swift
import UIKit import NCMB //////////////// ▼▼ 追加 ▼▼ //////////////// import MessageUI //////////////// ▲▲ 追加 ▲▲ ////////////////
//////////////// ▼▼ プロトコル追加 ▼▼ //////////////// class UserDetailViewController: UIViewController,MFMailComposeViewControllerDelegate { //////////////// ▲▲ プロトコル追加 ▲▲ //////////////// : : : : @IBAction func contact(sender: AnyObject) { //////////////// ▼▼ 追加 ▼▼ //////////////// //メールを送信できるかチェック if MFMailComposeViewController.canSendMail()==false { print("Email Send Failed") return } let mailViewController = MFMailComposeViewController() let toRecipients = [user.objectForKey("mailAddress") as! String] //Toのアドレス指定 mailViewController.mailComposeDelegate = self mailViewController.setSubject("「出会いアプリ」メール通知") mailViewController.setToRecipients(toRecipients) //Toアドレスの表示 mailViewController.setMessageBody("", isHTML: false) // 画像追加 let fbPictureUrl = "https://graph.facebook.com/" + NCMBUser.currentUser().userName + "/picture?type=large" if let fbpicUrl = NSURL(string: fbPictureUrl) { if let data = NSData(contentsOfURL: fbpicUrl) { mailViewController.addAttachmentData(data, mimeType: "image/png", fileName: "image") } } self.presentViewController(mailViewController, animated: true, completion: nil) //////////////// ▲▲ 追加 ▲▲ //////////////// }
//////////////// ▼▼ 追加 ▼▼ //////////////// // メール完了時 func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) { switch result { case MFMailComposeResultCancelled: print("メール送信キャンセル") break case MFMailComposeResultSaved: print("メールドラフト保存") break case MFMailComposeResultSent: print("メール送信完了") break case MFMailComposeResultFailed: print("メール送信失敗") break default: break } // 画面を閉じる self.dismissViewControllerAnimated(true, completion: nil) } //////////////// ▲▲ 追加 ▲▲ //////////////// }
|
これでRunして動作確認してみましょう。下図のように「連絡する」ボタンをタップしたらメール送信画面が表示されればOKです。

これでアプリは完成です。お疲れ様でした。