我正在尝试使用特殊的类方法(XYZperson
或+(insatncetype)iniPersonDefault:
)初始化名为+(instancetype)initWithFirstName...
的类的实例(person1,person2),以便使用firstName
以及lastName
和dateOfBirth
(不要担心出生日期是NSString
对象,一旦有效,我会改变它。
为方便起见,将这些先前的对象“变量”封装在一个数组中,如下面的代码所示。
我这样做是因为我明白在类方法中处理实例变量是不可能的,所以接口文件中没有@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 =@[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-05-11 12:30:28.258 fonctiontest [4317:303] John Doe 1234 et Henry V 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
的数组上调用最后一个方法?任何的想法?
我是初学者所以如果整个逻辑搞砸了,请告诉我如何。
答案 0 :(得分:2)
您无法使用self
从类方法访问实例方法或变量,例如[self saySomething:greeting]
在类方法中不起作用。但是,如果该类方法作为参数发送了对象实例,或者它创建了一个新实例,那么您当然可以从类方法访问实例成员。
您似乎希望实现类工厂方法来创建XYZPerson的实例。我建议阅读这些documentation,因为这是Objective-C中一个重要的概念来理解。实际上,我建议现在阅读{{3>}的定义类和使用对象部分(最后应该读取整个文档),这样你就可以理解了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
注意:
initPersonDefault
重命名为person
,以遵循类工厂方法的命名约定之一。以init
开头的方法应该始终是实例方法self
指针访问所有这些数据实现:
@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
[[self alloc] init...]
来创建一个对象,该对象是该类的一个对象,然后根据需要将给定或默认数据传递给init方法以初始化该对象,然后返回该实例。请注意,由于这是一个类方法,self指的是XYZPerson类,而不是XYZPerson对象,因此[self alloc]
有点像[XYZPerson alloc]
(忽略子类的可能性),这就是我们的方式创建一个返回XYZPerson实例if (self = [super init])
检查是一个重要模式,它调用基类中的init方法(此处为NSObject)并确保它不返回nil
sayHello
的示例实施。此方法不再需要参数,因为它可以通过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;
}
[[XYZPerson alloc] init...]
正确创建XYZPerson实例并使用其初始化程序。请注意此代码与上面+person
方法sayHello
是发送到person1
实例的消息。这会调用person1对象上的sayHello方法,这是该方法访问firstName等的方式,而不会在此处传递额外的参数关于原始帖子中出现的错误的说明:由于您从该init方法返回NSArray而不是XYZPerson对象,因此在发送{时,会发送无法识别的选择器发送到实例错误{1}}消息发送到sayHello
变量,因为person1指向没有sayHello实现的NSArray。