Sean's Note: 11月 2014

2014年11月18日 星期二

[iOS8] How to show menu(Cut, Copy, Paste or custom action) when long pressing the cell of UITableView?

如果是用 UITableViewCell,只需要 override 三個方法:

//
// CustomUITableView.m
//

- (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath {
    return YES;
}

//
// CustomUITableView.m
//

- (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath {
    return YES;
}

-(BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
    return YES;
}

//  Need to override even perform nothing.
- (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
    if (action == @selector(copy:)) {
        UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
        UIPasteboard *pasteBoard = [UIPasteboard generalPasteboard];
        [pasteBoard setString:cell.textLabel.text];
    }
}

長按 cell 後就會跳出 Cut, Copy 和 Paste:

圖1. UIMenuController

但如果要設定自己的 menu item 如果不 subclass UITableCellView,長按 cell 也只會跳出 

Cut, Copy 和 Paste,不會看到自己透過 setMenuItems 所加入的 UIMenuItem。

這時就需要 subclass UITableCellView:

//
// CustomUITableView.m
//

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    UIMenuItem *testMenuItem = [[UIMenuItem alloc] initWithTitle:@"Test" action:@selector(test:)];    
    [[UIMenuController sharedMenuController] setMenuItems: @[testMenuItem]];
    [[UIMenuController sharedMenuController] update];
}

//
// CustomUITableViewCell.m
//

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender{
     NSLog(@"CustomTableViewCell: %@\n", NSStringFromSelector(action));
    // There will be lots of default items if don't check.
    if (action == @selector(copy:) || action == @selector(test:))
        return YES;
    return NO;
}

// It's said need to be overrode from forums, but test ok without overriding it.
//-(BOOL)canBecomeFirstResponder {
//    return YES;
//}

/// this methods will be called for the cell menu items
-(void) test: (id) sender {
    NSLog(@"CustomTableViewCell: test!");
}

2014年11月14日 星期五

Class Extensions Extend the Internal Implementation

常會看到在 .h 和 .m 檔裡都有 @interface 的敘述,一開始覺得很納悶,@interface
不是只要寫在 .h 就好了嗎?不過仔細看又略有不同,在 .m 的 @interface 敘述後面還多了
小括號 ()。

// Classname.m

@interface Classname() {
    id _instanceVar;
}

@property NSObject *extraProperty;

@end

原來這種用法叫做類別延伸 (class extenstion)。好處在於可以定義額外的 property, 實體
變數(需要定義在大括號裡)和方法來擴充類別,而在這個匿名的 category 所以定義的方法,
必須在這個類別的 implementation 區段實作。這些 private 的方法和 property 讓類別延伸也符合了 OO 中封裝 (Encapsulation) 的精神,不需要將實作的資料和內容被看見。
另外一個常見的 property 用法便是對外宣告為 readonly 對內為 readwrite:

// XYZPerson.h

@interface XYZPerson : NSObject
...
@property (readonly) NSString *uniqueIdentifier;
- (void)assignUniqueIdentifier;
@end

// XYZPerson.m 

@interface XYZPerson ()
@property (readwrite) NSString *uniqueIdentifier; // readwrite 是 default 的屬性所以也可省略不寫
@end

@implementation XYZPerson
...
@end

2014年11月12日 星期三

How to get asset's information from the device?

在 iOS 4.0 之後,ALAsset 這個類別提供了 - valueForProperty 方法來取得 asset 的資訊,

文件裡定義了八種:

NSString *const ALAssetPropertyType ;
NSString *const ALAssetPropertyLocation ;
NSString *const ALAssetPropertyDuration ;
NSString *const ALAssetPropertyOrientation ;
NSString *const ALAssetPropertyDate ;
NSString *const ALAssetPropertyRepresentations ;
NSString *const ALAssetPropertyURLs ;
NSString *const ALAssetPropertyAssetURL;
咦?怎麼沒有名稱 Name 呢?

想要取得名稱和檔案大小其他的資訊得透過 ALAssetRepresentation 來取得。

ALAssetRepresentation *rep = [asset defaultRepresenttion];
[rep filename];
[rep size];

What is the use of "#pragma mark" in codes?

程式中的 #pragma mark 本身對程式碼並無意義,僅用來幫助組織編排程式,

方便將一群方法分類,以便於在 Jump bar 中快速查詢。

例如:

#pragma mark - 即是加一條分隔線。
#pragma mark Initialization 即是將以下的方法列於 Initialization 標題之下。

圖1. Jump bar

2014年11月11日 星期二

[Xcode 6.1] Be careful with the order of "First Item" and "Second Item" when editing constraint

根據官方的文件, space constraint 的數學公式如下:

FirstItem.Attribute1 = (SecondItem.Attribute2 * Multiplier) + Constant

所以對調 "First Item" 跟 "Second Item" 的結果將會不同,

以圖1 為例 Superview.Trailing = (Text Filed.Trailing * 1 ) + 10,

代表有一個 Text Filed 元件的右邊將會置於父視圖的右邊數來 10 個單位距離。

圖1. Space Constraint
但若將兩者對調,將變成 Text Filed.Trailing = ( Superview.Trailing* 1 ) + 10,

最後的結果,Text Filed 元件右邊的位置將會超出父視圖的範圍。

Ref: https://developer.apple.com/library/ios/recipes/xcode_help-IB_auto_layout/chapters/EditingConstraintAttributesintheAttributesInspector.html

[Xcode Common Errors] Failed to instantiate the default view controller for UIMainStoryboardFile 'Main' ...

當 console 出現下列訊息時:

Failed to instantiate the default view controller for UIMainStoryboardFile 'Main' - perhaps the designated entry point is not set?

檢查看看第一個 View Controller 的 Attributes Inspector 頁面 "Is Initial View Controller"

是否忘了勾選?

圖1. Attributes Inspector