2016年1月17日 星期日

iOS筆記:UICollectionViewCell的一些問題

遇到的問題:[UICollectionViewCell imageCell]: unrecognized selector sent to instance

當客製化自己的CollectionViewCell時一定要記得修改viewDidLoad底下的cell名稱.

- (void)viewDidLoad {
    [super viewDidLoad];

    // Register cell classes, 自己客制的cell要記得改這裡!!
    [self.collectionView registerClass:[yourCollectionViewCell class] forCellWithReuseIdentifier:reuseIdentifier];
}

問題:Storyboard CollectionView segue not being triggered

明明Cell有拉Segue但是怎麼點都不會前進到下一個View.

Root cause: Cannot create segues directly from cells in a storyboard because the CollectionView is populated dynamically through the data source.

Solution: Should use the collectionView:didSelectItemAtIndexPath: and perform the segue programatically using performSegueWithIdentifier:sender:.

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
    [self performSegueWithIdentifier:@"MySegueIdentifier" sender:self];
}

2016年1月16日 星期六

iOS筆記:Parse and Facebook SDK

這部分的流程會根據iOS的版本而有誤, 建議還是按照Parse跟Facebook官方的文件來做即可.

目的:使用 Parse 的 Facebook 登入功能.

enter image description here

a. 利用cocoapods來管理Framework. 在新開的專案中新增“Podfile”, 接著執行 pod install.

ParseFacebookUtilsV4 會選用1.8.5是因為我在使用最新版本的時候遇到了一些編譯上的問題, 但這問題在這一版不存在.

platform :ios, '9.0'

pod 'Parse'
pod 'FBSDKCoreKit'
pod 'FBSDKLoginKit'
pod 'FBSDKShareKit'
pod 'ParseFacebookUtilsV4', "~> 1.8.5"

b. 設定Parse
先去Parse官網自訂一個APP名稱.
enter image description here

接著照著以下的設定步驟:
https://parse.com/apps/quickstart#parse_data/mobile/ios/native/new

AppDelegate.m中的application:didFinishLaunchingWithOptions:中新增, 並且#import <Parse.h>.

[Parse setApplicationId:@"eEUFWMCQjmRTAFXXXXXXXSI0JYJ"
                  clientKey:@"BKko60sluQisKwSvyEyKOFrXXXXXXXXXXXX"];

c. Setting up Facebook
使用 Facebook 登入功能,基本上分成三步:

  1. https://developers.facebook.com 創立一個新應用。

enter image description here

只要照著步驟設定即可.
enter image description here

記得在Setting中輸入mail去enable APP.

enter image description here

  1. 透過 CocoaPods 把 Facebook 相關的Library加入專案裡。
  2. 最後就是把登入功能加到 ViewController 裡面。
    Parse provides an easy way to integrate Facebook with your application.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    //...

    [PFFacebookUtils initializeFacebookWithApplicationLaunchOptions:launchOptions];

    [[FBSDKApplicationDelegate sharedInstance] application:application
                             didFinishLaunchingWithOptions:launchOptions];

    return YES;
}

- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation {
    return [[FBSDKApplicationDelegate sharedInstance] application:application
                                                          openURL:url
                                                sourceApplication:sourceApplication
                                                       annotation:annotation];
}

PFUser

The PFUser class is a local representation of a user persisted to the Parse Data.

- (void)updateUserInformation
{
    if ([FBSDKAccessToken currentAccessToken]) {
        [[[FBSDKGraphRequest alloc] initWithGraphPath:@"me" parameters:@{@"fields" : @"name,first_name,gender,birthday,location"}]
//從Facebook那讀取上述的使用者資料

         startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
             if (!error) {
                 NSDictionary *userDictionary = (NSDictionary *)result;

                 //Create URL
                 NSString *facebookID = userDictionary[@"id"];
                 NSURL *pictureURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://graph.facebook.com/%@/picture?type=large&return_ssl_resources=1", facebookID]];

                 NSLog(@"%@",userDictionary);

                 NSMutableDictionary *userProfile = [[NSMutableDictionary alloc] initWithCapacity:7];

                 if (userDictionary[@"name"]) {
                     userProfile[PFUserProfileNameKey] = userDictionary[@"name"];
                 }
                 if (userDictionary[@"first_name"]) {
                     userProfile[PFUserProfileFirstNameKey] = userDictionary[@"first_name"];
                 }
                 if (userDictionary[@"location"][@"name"]) {
                     userProfile[PFUserProfileLocationKey] = userDictionary[@"location"][@"name"];
                 }
                 if (userDictionary[@"gender"]) {
                     userProfile[PFUserProfileGenderKey] = userDictionary[@"gender"];
                 }
                 if (userDictionary[@"birthday"]) {
                     userProfile[PFUserProfileBirthdayKey] = userDictionary[@"birthday"];
                 }
                 if ([pictureURL absoluteString]) {
                     userProfile[PFUserProfilePictureURL] = [pictureURL absoluteString];
                 }

                 [[PFUser currentUser] setObject:userProfile forKey:PFUserProfileKey];
                 [[PFUser currentUser] saveInBackground];

                 [self requestImage];
             }
             else {
                 NSLog(@"Error in Facebook Request %@", error);
             }

         }];
    }
}

如何抓取使用者的照片並呈現出來

主要是使用NSURLSession的NSURLSessionDownloadTask來顯示image.

- (void)uploadPFFileToParse:(UIImage *)image
{
    NSData *imageData = UIImageJPEGRepresentation(image, 0.8);

    if (!imageData) {
        NSLog(@"imageData was not found");
        return;
    }

    PFFile *photoFile = [PFFile fileWithData:imageData];

    [photoFile saveInBackgroundWithBlock:^(BOOL succeeded, NSError * _Nullable error) {
        if (succeeded) {
            PFObject *photo = [PFObject objectWithClassName:PFPhotoClassKey];
            [photo setObject:[PFUser currentUser] forKey:PFPhotoUserKey];
            [photo setObject:photoFile forKey:PFPhotoPictureKey];
            [photo saveInBackgroundWithBlock:^(BOOL succeeded, NSError * _Nullable error) {
                NSLog(@"Photo save successfully");
            }];
        }
    }];
}

- (void)requestImage
{
    PFQuery *query = [PFQuery queryWithClassName:PFPhotoClassKey];
    [query whereKey:PFPhotoUserKey equalTo:[PFUser currentUser]];
    [query countObjectsInBackgroundWithBlock:^(int number, NSError * _Nullable error) {
        if (number == 0) {
            PFUser *user = [PFUser currentUser];

            self.imageData = [[NSMutableData alloc] init];

            NSURL *profilePictureURL = [NSURL URLWithString:user[PFUserProfileKey][PFUserProfilePictureURL]];

            NSURLSession *session = [NSURLSession sharedSession];

            NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:profilePictureURL completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                UIImage *downloadedImage = nil;
                if (!error) {
                    downloadedImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:location]];
                } else {
                    NSLog(@"downloadTaskWithRequest failed: %@", error);
                    return;
                }

                dispatch_async(dispatch_get_main_queue(), ^ {
                    UIImage *profileImage = downloadedImage;
                    [self uploadPFFileToParse:profileImage];
                });
            }];
            [downloadTask resume];
        }
    }];
}

遭遇過的問題如下:
1.Could not build module ‘FBSDKCoreKit’
http://stackoverflow.com/questions/29466683/could-not-build-module-fbsdkcorekit-for-facebooksdk-4/29466739#29466739

2.Duplicate symbols for architecture x86_64
http://stackoverflow.com/questions/29466683/could-not-build-module-fbsdkcorekit-for-facebooksdk-4

3.Facebook Friend List Save As Array to Parse
http://stackoverflow.com/questions/32951433/facebook-friend-list-save-as-array-to-parse-swift

4.In developer.facebook.com, APP’s show “Not available to all users because your app is not live.”
http://stackoverflow.com/questions/21329250/the-developers-of-this-app-have-not-set-up-this-app-properly-for-facebook-login

5.How to get user email address from FBSDKProfile in Facebook SDK 4.0.
http://stackoverflow.com/questions/31410793/ios-facebook-sdk-login-doesnt-return-email-despite-permissions-granted/31503463#31503463

http://stackoverflow.com/questions/29323244/facebook-ios-sdk-4-0how-to-get-user-email-address-from-fbsdkprofile

參考網址:
1. https://developers.facebook.com/
2. https://www.parse.com/apps
3. http://blog.winwu.today/2014/05/ios-facebooksdk-facebook.html
4. https://swiftlyios.com/swift-parse-login-signup/
5. https://swiftlyios.com/parse-facebook-login-register/
6. https://www.parse.com/docs/ios/guide

2016年1月2日 星期六

Git指令:Review

Git with GitHub

Upload to Github

git init
git add README.md
git commit -m "first commit"
git remote add origin git@github.com:username/XXX.git
git push -u origin master

常用的指令

$ git status
$ git diff
$ git log  //看下過的commit
$ git tag "tag name" //幫一長串的commit改ID
$ git checkout "commit" //變回"commit(一串id)" or Head
$ git rm "..." //刪除"..."
$ git mv "..." //移動檔案

Branch

$ git checkout -b [name_of_your_new_branch]
 //把新建的分支取名為branchname並移動到分支上
$ git branch [name_of_your_new_branch]
 // 新建一個branch叫
$ git checkout [name_of_your_new_branch]
 //移動到branch上
$ git branch -d [name_of_your_new_branch]
 //刪除
$ git branch //列出所有的branch
$ git branch -v //查看各個分支最後一個提交物件的資訊
$ git branch --merged //哪些分支是當前分支的直接上游

Push the branch on github :

$ git push origin [name_of_your_new_branch]

$ git push origin :[name_of_your_new_branch] //刪除遠端分支
$ git remote show origin  //監看遠端儲存庫

Stash

git stash //把目前工作區的東西丟到暫存區裡,等之後在回來拿他
git stash list //列出所有暫存區的資料
git stash pop //取出最新的一筆, 並移除.
git stash apply //取出最新的一筆 stash 暫存資料. 但是 stash 資料不移除
git stash clear //把 stash 都清掉

Merge & Rebase

Merge a branch back.

//回到 master 分支,利用 git merge 命令指定要合併進來的分支
$ git checkout master
$ git merge [name_of_your_new_branch]

Rebase概念請參考:https://git-scm.com/book/zh-tw/v1/Git-%E5%88%86%E6%94%AF-%E5%88%86%E6%94%AF%E7%9A%84%E8%A1%8D%E5%90%88

雖然最後整合得到的結果跟merge沒有區別,但rebase能產生一個更為整潔的提交歷史。