You can't access instance methods or variables from a class method using self
, e.g. [self saySomething:greeting]
would not work from within a class method. However, you can certainly access instance members from a class method if that class method is sent an object instance as a parameter, or if it creates a new instance.
It seems that you want to implement class factory methods to create instances of XYZPerson. I suggest reading the documentation on these, as it is an important concept in Objective-C to understand. Actually, I would suggest reading the Defining Classes and Working with Objects sections of Programming with Objective-C now (and eventually the entire document should be read), so you can understand how alloc/init works and how to properly define and work with your objects.
Here is a suggested class definition for your .h file, annotated with notes:
@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
Notes:
- Renamed
initPersonDefault
to justperson
, to follow one of the naming conventions for class factory methods. Methods starting withinit
should always be instance methods - Changed initWithFirstName... to an instance method (+ to -)
- Fixed capitalization of the selector
- The revised init method is going to return an instance of XYZPerson, not NSArray. The values it was given are stored as properties of the XYZPerson instance
- Not sure what the implementation of sayHello is, but now that we have properties defined for name/DOB, the sayHello method can access all this data via the
self
pointer
Implementation:
@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
- Class factory methods typically use
[[self alloc] init...]
to create an object that is an istance of that class, and then pass given or default data to the init method as needed to initialize that object, then return that instance. Note here that since this is a class method, self refers to the XYZPerson class, not an XYZPerson object, thus[self alloc]
is sort of like[XYZPerson alloc]
(ignoring the possibility of subclasses), which is how we are creating an returning an XYZPerson instance - The
if (self = [super init])
check is an important pattern, it calls the init method in the base class (NSObject here) and ensures it did not returnnil
- Here we are using the properties defined in the .h file. We are storing copies of first name/last name/DOB with the instance of XYZPerson that is being initialized
- Returning an XYZPerson object, not NSArray
- Sample implementation of
sayHello
. This method no longer needs an argument because it can access the name and DOB properties viaself
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;
}
- Using the renamed factory method here
- Use
[[XYZPerson alloc] init...]
to properly create an instance of XYZPerson and use its initializer. Note the similarity between this code and the implementation of the+person
method above - Now you can access firstName, lastName, dateOfBirth using dot notation. You'll know it's working properly because Xcode will auto-complete the property names after you type the dot
sayHello
is a message sent to theperson1
instance. This invokes the sayHello method on the person1 object, which is how that method has access to firstName, etc., without passing an additional argument here
A note about the errors you got in your original post: since you are returning an NSArray rather than XYZPerson object from that init method, you get the unrecognized selector sent to instance error when sending the sayHello
message to the person1
variable, because person1 is pointing to an NSArray which has no implementation of sayHello.