2014-05-11 62 views
0

我試圖通過一個特殊的類方法(+(insatncetype)iniPersonDefault:+(instancetype)initWithFirstName...)調用一個名爲XYZperson的類的實例(person1,person2),以便初始化這些實例一個firstNamelastNamedateOfBirth(不要擔心分娩是一個NSString對象在這裏的日子,我會改的,一旦它的工作原理)Obj-C,初始化階段,從類方法到實例方法

爲了方便封裝陣列中的那些以前的對象「變量」,如圖下面的代碼。

我這樣做,因爲我理解,這是不可能的應對類方法在接口文件所以沒有@property實例變量:

.m文件:

#import "XYZPerson.h" 

@implementation XYZPerson 

// init methods 

+(instancetype)initPersonDefault 
{ 
    return [self initWithFirstName:@"John" LastName:@"Doe" DateOfBirth:@"1234"]; 
} 

+(id)initWithFirstName:(NSString *)aFristName 
       LastName:(NSString *)aLastName 
      DateOfBirth:(NSString *)aDateOfBirth 
{ 
    if (self == [XYZPerson class]) 
    { 
     NSString *firstName2 = aFristName; 
     NSString *lastName2 = aLastName; 
     NSString *dateOfBirth2 = aDateOfBirth; 
     NSArray *info [email protected][firstName2,lastName2,dateOfBirth2]; 

     //return [NSString stringWithFormat:@" %@ %@ born in %@", info[0], info[1], info[2] ]; 
     //  return (NSString *)lastName2; 
     //  return (NSString *)dateOfBirth2; 
     return (NSArray *)info; 
    } 
    return [[self alloc]init]; 
} 

// Other methods 

-(void)saysomething : (NSString *)greeting 
{ 
    NSLog(@"%@ ", greeting); 
} 

-(void)sayHello: (NSArray *)infoP 
{ 
    NSString *results =[[infoP valueForKey:@"description"] componentsJoinedByString:@" "]; 
    [self saysomething:results]; 
} 

.h文件:

#import <Foundation/Foundation.h> 

@interface XYZPerson : NSObject 

-(void)saysomething : (NSString *) greeting; 

-(void)sayHello: (NSArray *)infoP; 

+ (id)initWithFirstName:(NSString *)aFristName 
       LastName:(NSString *)aLastName 
      DateOfBirth:(NSString *)aDateOfBirth; 

+(instancetype)initPersonDefault; 

@end 

只要我嘗試訪問與實例方法的對象變量,我很困惑,這裏是main.m

#import <Foundation/Foundation.h> 
#import "XYZPerson.h" 
#import "XYZShoutingPerson.h" 

int main(int argc, const char * argv[]) 
{ 
    @autoreleasepool { 
     XYZPerson *person1 = [XYZPerson initPersonDefault]; 
     XYZPerson *person2 = [XYZPerson initWithFirstName:@"Henry" LastName:@"V" DateOfBirth:@"1234"]; 

     NSLog(@" %@ et %@", [[person1 valueForKey:@"description"] componentsJoinedByString:@" "], 
          [[person2 valueForKey:@"description"] componentsJoinedByString:@" "]); 

     [person1 sayHello: person1]; 
    } 
    return 0; 
} 

這裏是我的控制檯:

2014年5月11日12:30:28.258 fonctiontest [4317:303]李四1234等亨利五世1234
2014- 05-11 12:30:28.278 fonctiontest [4317:303] - [__ NSArrayI sayHello:]:無法識別的選擇器發送到實例0x102617a20
2014-05-11 12:30:28.279 fonctiontest [4317:303] ***終止應用程序由於未捕獲的異常'NSInvalidArgumentException',原因:' - [__ NSArrayI sayHello:]:無法識別的選擇器發送到實例0x102617a20'

...

更確切地說,我得到一個警告說:

不兼容的指針類型發送「XYZPerson *爲鍵入 '的NSArray *'

的參數所以我的猜測是person1有一個複雜的狀態,它是類XYZPerson的一個實例,它也包含一個數組。將它傳遞給-(void)sayHello : (NSArray *)infoP方法中的指針infoP時,它不起作用。我想不出在person1這個數組上調用最後一個方法該怎麼做?任何想法?

我是一個初學者,所以如果整個邏輯搞砸了,請讓我知道如何。

+1

你永遠不會分配你的實例。 init方法應該是實例方法,您可以通過向該類發送+ alloc創建一個未初始化的實例。 – nielsbot

+0

感謝nielsbot! – Jules

回答

2

您不能使用self(例如,)使用類方法訪問實例方法或變量。 [self saySomething:greeting]在類方法中不起作用。但是,如果該類方法將對象實例作爲參數發送,或者創建了新實例,那麼您肯定可以從類方法中訪問實例成員。

看來你想實現類工廠方法來創建XYZPerson的實例。我建議閱讀documentation,因爲這是Objective-C中的一個重要概念。實際上,我建議您閱讀定義類使用對象Programming with Objective-C的部分現在(並且最終應該讀取整個文檔),因此您可以瞭解alloc/init如何工作以及如何正確定義和使用對象。

這裏是您的.h文件中建議類的定義,與筆記註釋:

@interface XYZPerson : NSObject 

// 1 
+ (instancetype)person; 

// 2 
- (id)initWithFirstName:(NSString *)aFirstName 
       lastName:(NSString *)aLastName // 3 
      dateOfBirth:(NSString *)aDateOfBirth; 

// 4 
@property (copy, nonatomic) NSString *firstName; 
@property (copy, nonatomic) NSString *firstName; 
@property (copy, nonatomic) NSString *dateOfBirth; 

- (void)saysomething: (NSString *) greeting; 

// 5 
- (void)sayHello; 

@end 

注:

  1. 更名initPersonDefault只是person,遵循命名約定類之一工廠方法。開始init方法應該永遠是實例方法
  2. 改變initWithFirstName ...實例方法(+到 - )
  3. 固定選擇
  4. 修訂後的init方法會返回XYZPerson的一個實例的資本,不是NSArray。它被賦予存儲爲XYZPerson實例
  5. 不知道是什麼的sayHello的實現,但現在我們有一個名稱/ DOB定義的屬性properties值,sayHello方法可以通過self指針
  6. 訪問所有數據

實現:

@implementation XYZPerson 

+ (instancetype)person 
{ 
    // 1 
    return [[self alloc] initWithFirstName:@"John" 
            lastName:@"Doe" 
           dateOFBirth:@"1234"]; 
} 

- (id)initWithFirstName:(NSString *)aFirstName 
       lastName:(NSString *)aLastName 
      dateOfBirth:(NSString *)aDateOfBirth 
{ 
    // 2 
    if (self = [super init]) { 
     // 3 
     self.firstName = aFirstName; 
     self.lastName = aLastName; 
     self.dateOfBirth = aDateOfBirth; 
    } 
    return self; // 4 
} 

- (void)sayHello 
{ 
    // 5 
    NSLog(@"Hello, I am %@ %@", self.firstName, self.LastName); 
} 

... 
@end 
  1. 工廠類方法通常使用[[self alloc] init...]創建一個對象,它是類的一個istance,然後通過給定的或默認數據提供給init方法根據需要初始化該對象,然後返回該實例。請注意,由於這是一個類方法,self指的是XYZPerson類,而不是XYZPerson對象,因此[self alloc]有點像[XYZPerson alloc](忽略子類的可能性),這就是我們如何創建返回一個XYZPerson實例
  2. if (self = [super init])檢查是一個重要的模式,它調用基類中的init方法(NSObject的位置),並確保它未返回nil
  3. 在這裏,我們使用的是性質在.h文件中定義的。我們首先存儲名稱/姓名/ DOB的副本與正在初始化
  4. 返回一個XYZPerson對象,而不是NSArray的
  5. 樣品實施sayHello XYZPerson的實例。這種方法不再需要一個自變量,因爲它可以通過self

的main.m訪問名字和出生日期屬性:

#import <Foundation/Foundation.h> 
#import "XYZPerson.h" 
#import "XYZShoutingPerson.h" 

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

     // 1 
     XYZPerson *person1 = [XYZPerson person]; 
     // 2 
     XYZPerson *person2 = [[XYZPerson alloc] initWithFirstName:@"Henry" LastName:@"V" DateOfBirth:@"1234"]; 

     // 3 
     NSLog(@" %@ et %@", person1.firstName, person1.lastName, person1.dateOfBirth); 

     // 4 
     [person1 sayHello]; 
    } 
    return 0; 
} 
  1. 使用這裏改名爲工廠方法
  2. 使用[[XYZPerson alloc] init...]正常創建一個XYZPerson的實例並使用它的初始化程序。請注意,此代碼與上述方法的實現之間的相似性
  3. 現在您可以使用點符號訪問firstName,lastName,dateOfBirth。你會知道它工作正常,因爲Xcode會在你輸入點後自動完成屬性名稱
  4. sayHello是發送到person1實例的消息。這將調用PERSON1對象,這是該方法如何訪問名字,等上sayHello方法,沒有路過此處的附加參數

的注意事項有關你在原來的職位得到了錯誤:由於您從該init方法返回一個NSArray而不是XYZPerson對象,因此在將sayHello消息發送到person1變量時,您會收到無法識別的選擇器發送到實例錯誤,因爲person1指向的是沒有實現sayHello的NSArray。

+0

非常感謝,真的很有幫助,我會重新仔細閱讀這兩章! – Jules

+0

你完全解決了我的問題,非常感謝你的時間和清楚的解釋。 – Jules