天天看點

IOS開發學習筆記(十二)——ObjectC中的複雜類型

簡單類型就不說了,基本上每個語言都差不多。本次我們僅讨論非簡單資料類型。

類的繼承

頭檔案

#import <Foundation/Foundation.h>

// MyDummy類從NSObject繼承而來
@interface MyDummy : NSObject

/*
 * '-'辨別是執行個體方法而不是靜态方法;
 * 傳回值用'()'括号括起來,後面跟上方法名;
 * 冒号後跟上第一個參數類型(繼續使用括号括起來)和參數
 * 空格後跟第二個參數+冒号+類型+參數名
 * 最後用分号結束
 */
- (void)foo:(NSString *)username password:(NSString *)passwd;

@end
           

實作檔案

#import "MyDummy.h"

@implementation MyDummy

/*
 * 根據聲明生成
 */
-(void)foo:(NSString *)username password:(NSString *)passwd {
    NSLog(@"Your name is %@, your password is %@", username, passwd);
}

@end
           

測試檔案

#import <Foundation/Foundation.h>
#import "MyDummy.h"

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        NSString *username = [[NSString alloc] initWithFormat:@"Sam"];
        NSString *password = [[NSString alloc] initWithFormat:@"sssssssssss"];
        
        MyDummy *dummy = [[MyDummy alloc] init];
        
        [dummy foo:username password:password];
        
    }
    return 0;
}
           

Category

category和繼承有部分類似,不過相對來說比繼承關系要簡單,我們看一下:

頭檔案

#import "MyDummy.h"

// 注意聲明方式與繼承不同
@interface MyDummy (MyDummy_SayHello)
// 方法的聲明方式完全相同
-(void) sayHello:(NSString *)username password:(NSString *)password;

@end
           

實作檔案

#import "MyDummy+MyDummy_SayHello.h"

@implementation MyDummy (MyDummy_SayHello)

-(void) sayHello:(NSString *)username password:(NSString *)password {
    // 直接調用現有Dummy方法
    return [self foo:username password:password];
}

@end
           

測試檔案

#import <Foundation/Foundation.h>
#import "MyDummy.h"
#import "MyDummy+MyDummy_SayHello.h"

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        NSString *username = [[NSString alloc] initWithFormat:@"Sam"];
        NSString *password = [[NSString alloc] initWithFormat:@"sssssssssss"];
        // 聲明一個Dummy類的對象
        MyDummy *dummy = [[MyDummy alloc] init];
        // 對象的方法被擴充了
        [dummy sayHello:username password:password];
        
    }
    return 0;
}
           

Protocol--協定

Protocol在java中對應的是接口。我們在ObjectC中這樣使用:

定義protocol

#import <Foundation/Foundation.h>

@protocol IComparable <NSObject>

-(int) compare:(NSObject *)other;

@end
           

實作類的頭檔案

#import <Foundation/Foundation.h>
#import "IComparable.h"

@interface MyNumber : NSObject <IComparable>

@property int num;

-(int) compare:(NSObject *)other;

@end
           

實作類的實作檔案

#import "MyNumber.h"
#import "IComparable.h"

@implementation MyNumber

@synthesize num;

-(int) compare:(NSObject *)other {
    MyNumber *number = (MyNumber *) other;
    
    return [self num] - [number num];
}

@end
           

測試類

#import <Foundation/Foundation.h>
#import "MyDummy.h"
#import "MyDummy+MyDummy_SayHello.h"
#import "MyNumber.h"

int main(int argc, const char * argv[])
{

    @autoreleasepool {

        MyNumber *num1 = [[MyNumber alloc] init];
        MyNumber *num2 = [[MyNumber alloc] init];
        
        [num1 setNum:10];
        [num2 setNum:100];
        
        NSLog(@"the number is %d", [num1 compare: num2]);
    }
    return 0;
}
           

id(動态類型)

ID類型很常見,例如alloc方法,init方法。ID類型很像以前Object Pascal中的variable類型,可以代表任意一種類型;或者你可以将他看成Java中的Object類型。但是一個很明顯的差别在于:Java是強類型語言,是以所有的類型轉換、方法調用都會檢查類型;但ObjectC中,隻要你将一個變量定義為id,那麼編譯器不會再做類型檢查工作,甚至連warning都不抛出。

我們看看代碼:

父類

#import <Foundation/Foundation.h>

@interface ParentClass : NSObject

@end
           
#import "ParentClass.h"

@implementation ParentClass

@end
           

第一個子類

#import "ParentClass.h"

@interface Child1 : ParentClass

-(void) foo1;

@end
           
#import "Child1.h"

@implementation Child1

-(void) foo1 {
    NSLog(@"foo1 invoked.");
}

@end
           

第二個子類

#import "ParentClass.h"

@interface Child2 : ParentClass

-(void) foo2;

@end
           
#import "Child2.h"

@implementation Child2

-(void) foo2{
    NSLog(@"foo2 invoked.");
}

@end
           

測試代碼

#import <Foundation/Foundation.h>
#import "ParentClass.h"
#import "Child1.h"
#import "Child2.h"

int main(int argc, const char * argv[])
{

    @autoreleasepool {

        NSLog(@"child1");
        Child1 *child1 = [[Child1 alloc] init];
        [child1 foo1];
        // 下面這一句無法編譯
        // [child1 foo2];
        
        NSLog(@"child2");
        id child2 = [[Child2 alloc] init];
        // 下面這一句會爆出異常
        // [child2 foo1];
        [child2 foo2];
        
        NSLog(@"child3");
        id child3 = [[Child2 alloc] init];
        // 下面這一段先判斷類型,之後調用,安全
        if ([child3 isKindOfClass:[Child1 class]]) {
            // 下面這句不會調用
            [child3 foo1];
        }
        // 下面這一段先判斷是否包含指定方法,之後調用,同樣安全
        if ([child3 respondsToSelector:@selector(foo2)]) {
            // 下面這句會調用
            [child3 foo2];
        }
    }
    return 0;
}
           

繼續閱讀