UITableViewCell accessoryType is not working

如題,不管Custom Cell或iOS原生的DefaultStyle Cell,都會發生accessoryType不管怎麼設定都無效的狀況,其實無關AutoLayout或XCode版本~
最需要注意的是,編輯狀態是否開啟!

假設某些row設定cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
當UITableView透過 setEditing:YES 開啟編輯狀態,UITableViewCellAccessoryDisclosureIndicator效果會因此不見,只剩下label text,且相對於UITableView的margin等layout呈現都會不同。

如果UITableView很複雜,想同時有編輯狀態又要保持accessoryType ,那麼就要仔細針對每個cell去設定編輯狀態,實際撰寫方式如下

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 1)
        return YES;
    else
        return NO;
}

- (UITableViewCellEditingStyle)tableView:(UITableView *)aTableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
    if(indexPath.section == 1) {
        if(indexPath.row == [self.myData count])
            return UITableViewCellEditingStyleInsert;
        else
            return UITableViewCellEditingStyleDelete;
    } else {
        return UITableViewCellEditingStyleNone;
    }
}

Get/Set a BOOL in the NSDictionary

Objective-C containers can store only Objective-C objects so you need to wrap you BOOL in some object.

Here is the Dictionary
NSMutableDictionary *dictionary1 =[[NSMutableDictionary alloc]init];
[dictionary1  setObject:[NSNumber  numberWithBool:false]  forKey:@"MyBoolValue"];

How to set bool value ?
[dictionary1  setObject:[NSNumber  numberWithBool:false]  forKey:@"MyBoolValue"];

How to get bool value ?
BOOL myValue = [dictionary1  objectForKey:@"MyBoolValue"]  boolValue];

如何改變iOS ActionSheet的字體顏色

承前文如何在iOS的ActionSheet加上圖片,再來記錄一下iOS 7、8改變字體顏色的方法

情境
ActionSheet共有三個Action為Create、Delete、Cancel
Create、Delete字體要是橘色,Cancel則是黑色

1. 舊版UIActionSheet
// ActionSheet程式碼
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil
                                                         delegate:self
                                                cancelButtonTitle:nil
                                           destructiveButtonTitle:nil
                                                otherButtonTitles:nil];
[actionSheet addButtonWithTitle:@"Create"];
[actionSheet addButtonWithTitle:@"Delete"];
[actionSheet addButtonWithTitle:@"Cancel"];
actionSheet.actionSheetStyle = UIActionSheetStyleDefault;
[actionSheet showInView:self.view];

// 變更顏色程式碼
- (void)willPresentActionSheet:(UIActionSheet *)actionSheet {
    // set color for each title
    for (UIView *subview in actionSheet.subviews) {
        if ([subview isKindOfClass:[UIButton class]]) {
            UIButton *button = (UIButton *)subview;
            if([button.titleLabel.text isEqual:@"Cancel")
                [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
            else
                [button setTitleColor:[UIColor orangeColor] forState:UIControlStateNormal];
        }
    }
}

2. 新版UIActionSheet
// ActionSheet程式碼
UIAlertController * actionSheetNew = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction* create = [UIAlertAction
                       actionWithTitle:@"Create"
                       style:UIAlertActionStyleDefault
                       handler:^(UIAlertAction * action)
                       {
                           // do something
                       }];
UIAlertAction* delete= [UIAlertAction
                       actionWithTitle:@"Delete"
                       style:UIAlertActionStyleDefault
                       handler:^(UIAlertAction * action)
                       {
                           // do something
                       }];
UIAlertAction* cancel= [UIAlertAction
                       actionWithTitle:@"Cancel"
                       style:UIAlertActionStyleDefault
                       handler:^(UIAlertAction * action)
                       {
                           // do something
                       }];
[actionSheetNew addAction:create];
[actionSheetNew addAction:delete];
[actionSheetNew addAction:cancel];
[self presentViewController:actionSheetNew animated:YES completion:nil];

// 變更顏色程式碼
[create setValue:[UIColor orangeColor] forKey:@"titleTextColor"];
[delete setValue:[UIColor orangeColor] forKey:@"titleTextColor"];
[cancel setValue:[UIColor blackColor] forKey:@"titleTextColor"];

另外,如果想要一次改變所有action的字體顏色,可以針對UIAlertController這樣寫
// 變更顏色程式碼(全部action)
actionSheetNew.view.tintColor = [UIColor orangeColor];

參考資料
如何在iOS的ActionSheet加上圖片

[Objective-C]Copy of Custom class

寫這篇的前因後果Java is 'pass by value'
這篇不談pass by reference、pass by value,或是Objective-C下的深拷貝、淺拷貝,網路上已經不少文章可參考,這邊直接透過最常見的ViewController傳值來演示會遇到的問題與解決辦法。

情境
●有二個ViewController:MainViewController、DetailViewController
●MainViewController有一個mutable的origionalArray,用途是呈現資料於tableview
●DetailViewController也有一個mutable的copyArray,用途是編輯資料於tableview,且資料是複製origionalArray來的
●當DetailViewController編輯結束後,用戶可以選擇"Save / Cancel"決定是否保留這次的編輯資料並回到上一頁MainViewController。若是,則copyArray會被用來更新origionalArray;若否,則不影響origionalArray

問題
●不管用戶選擇"Save / Cancel",origionalArray都會被copyArray影響

解法
●檢查MainViewController傳值的方式
DetailViewController *vc = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:nil];
// 寫法1
vc.copyArray= self.origionalArray;
// 寫法2
vc.copyArray= [self.origionalArray mutableCopy];
// 寫法3
vc.copyArray = [[NSMutableArray alloc] initWithArray:self.origionalArray copyItems:YES];
UINavigationController *navCon = [[UINavigationController alloc] initWithRootViewController:vc];
[self presentViewController:navCon animated:YES completion:nil];

寫法1或寫法2屬於淺拷貝,copyArray都沒有獨立於origionalArray,更新copyArray的同時也會更新origionalArray
這時候嘗試寫法3進行深拷貝,竟會報錯-[ManagementResponser copyWithZone:]: unrecognized selector sent to instance xxxxx 。那是因為origionalArray、copyArray所存放之資料為 'ManagementResponser' 自訂型別,要解決問題必須在custom class實作NSCopying,如何實作請看下圖

實作完成後,寫法3就能正常運行了。

參考資料
Pass-by-Value and Pass-by-Reference in Objective-C: A Refactoring Heuristic
--Copy Array相關
NSMutableCopying
mutable copy copies by reference, not value?
Objective-C: Copy Array, Modify Element (Object) in the Copy ONLY
NSMutableArray of custom classes copy
--NSCopying相關
Copying Objects in Objective-C
iOS OC NSCopying 协议
Objective-c的NSCopying协议

Java is 'pass by value'

昨天被Objective-C的pass by reference、pass by value折騰半天,才發現自己把Java的用法亂套在Objective-C  囧....

紀錄Objective-C之前,先轉錄Java方面正確的說明

[Objective-C] How to open URL ?

NSURL *url = [NSURL URLWithString:@"http://piggy-mylifemystyle.blogspot.com/"];

●使用WebView
    UIWebView *web=[[UIWebView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
    NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
    [web loadRequest:requestObj];
    [self.view addSubview:web];

●不使用WebView,直接開啟手機Safari
    [[UIApplication sharedApplication] openURL:url];

iOS Placeholder in UITextView

UITextField擁有placeholder屬性,所以能讓input呈現灰字hint的效果,UITextView卻沒有原生的方式可以直接設定,網路上有套SAMTextView可以參考,本文提供另一種比較簡單的方式。

●h file
@interface QuestionnaireBasicViewController : UIViewController

●m file
實作UITextViewDelegate內的二個method

- (void)textViewDidBeginEditing:(UITextView *)textView {
    if ([textView.text isEqualToString:NSLocalizedString(@"description", nil)]) {
        textView.text = @"";
        textView.textColor = [UIColor blackColor]; //optional
    }
}
- (void)textViewDidEndEditing:(UITextView *)textView {
    if ([textView.text isEqualToString:@""]) {
        textView.text = NSLocalizedString(@"description", nil);
        textView.textColor = [UIColor lightGrayColor]; //optional
    }
}

實際在m file使用
// placeholder for TxtView
myTextView.delegate = self;
myTextView.text = NSLocalizedString(@"description", nil);
myTextView.textColor = [UIColor lightGrayColor]; //optional

參考資料
Placeholder in UITextView

finish iOS UIViewController like Android

相信Android開發者都用過 finish() 將Activity從stack中銷毀,另一方就沒那麼幸運了,Objectice-C可沒有finish()讓開發者一指搞定。

情境描述如下
  A1ViewController
前往A2ViewController
前往A3ViewController
前往B1ViewController
前往B2ViewController,並且銷毀B1ViewController

本來的順序A1→A2→A3→B1→B2
後來的順序A1→A2→A3B2

要達到目標有二種作法
●自訂delegate
    在B1ViewController自訂delegate
    在A3ViewControoler實作delegate

    B1ViewController觸發delegate時呼叫
    [self.navigationController popViewControllerAnimated:NO];

    A3ViewController接到delegate時打開B2ViewController
    [self.navigationController pushViewController:B2ViewController animated:YES];

●UINavigationController的setViewControllers方法
    NSMutableArray * viewControllers = [self.navigationController.viewControllers mutableCopy];
    [viewControllers removeLastObject];
    [viewControllers addObject:B2ViewController];
   
    [self.navigationController setViewControllers:viewControllers animated:YES];


參考資料
equivalent of startactivity & finish in ios?
UINavigationController的setViewControllers方法

check in the Pods into source control ?

在Xcode搭配Git請參考這篇  將Xcode現有專案加入Git

如果專案有使用CocoaPods,.gitignore是否需要針對Pods處理呢?
答案是看你高興XD
只有Podfile 與 Podfile.lock一定要簽入版本控管,其他Pods就依照開發需求決定,簽入與否可參考CocoaPods的官方說明

Benefits of checking in the Pods directory
After cloning the repo, the project can immediately build and run, even without having CocoaPods installed on the machine. There is no need to run pod install, and no Internet connection is necessary.
The Pod artifacts (code/libraries) are always available, even if the source of a Pod (e.g. GitHub) were to go down.
The Pod artifacts are guaranteed to be identical to those in the original installation after cloning the repo.

Benefits of ignoring the Pods directory
The source control repo will be smaller and take up less space.
As long as the sources (e.g. GitHub) for all Pods are available, CocoaPods is generally able to recreate the same installation. (Technically there is no guarantee that running pod install will fetch and recreate identical artifacts when not using a commit SHA in the Podfile. This is especially true when using zip files in the Podfile.)
There won't be any conflicts to deal with when performing source control operations, such as merging branches with different Pod versions.
Whether or not you check in the Pods directory, the Podfile and Podfile.lock should always be kept under version control.

若上述優缺點還是無法協助你決定,可再參考stackoverflow的討論,看看哪種方式適合你~

參考資料
Should I check the Pods directory into source control?
What goes into your .gitignore if you're using CocoaPods?

Encoding and Decoding Objects

無論Android或Objective-C都會有自訂Data Model的應用

把object instance存放於記憶體是最常見的方式,二者的作法如下
Android:制定欄位 & getter/setter
Objective-C:制定欄位

但在下列場景一定要序列化
Android:二個頁面間傳值(例如activityA跳轉至activityB的時候要傳遞一個自訂data)
Objective-C:自訂data儲存於NSDefault

序列化方式
Android:implements Parcelable
Objective-C:implements NSCoding

參考資料
Archiving Objective-C Objects with NSCoding
Encoding and Decoding Objects

How to make "Done" button working on TextField keyboard

STEP 1 Setting 'Return Key' @ Attribute Inspector


STEP 2 Connect the IBAction


STEP 3 implement the IBAction


不要亂寫一堆程式碼污染專案,請用上述的方式完成喔 0.<