У меня есть простой вопрос о создании нескольких инициализаторов в объективном-c классе. В основном у меня есть класс, который представляет одну строку в моей базе данных (пользователи). У меня в настоящее время есть инициализатор, который инициализирует класс, основанный на пользователях UserID (который является также первичным ключом в базе данных), когда он передан UserID, класс будет их соединяться с веб-сервисом, разбирают результаты и возвращают объект, инициализированный к соответствующему ряду в базе данных.
В этой базе данных много уникальных областей (имя пользователя и emailaddress), я также хотел бы иметь возможность инициализировать свой объект, основанный на этих ценностях. Но я не уверен в том, как иметь больше чем один инициализатор, все, что я прочитал государства, что я свободен иметь несколько инициализаторов, пока каждый называет обозначенный инициализатор. Если бы кто-то мог бы выручить меня с этим, которое было бы большим.
Мой кодекс инициализатора следующие:
- (id) initWithUserID:(NSInteger) candidate {
self = [super init];
if(self) {
// Load User Data Here
NSString *soapMessage = [NSString stringWithFormat:
@"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
"<soap:Body>\n"
"<GetByUserID xmlns=\"http://tempuri.org/\">\n"
"<UserID>%d</UserID>\n"
"</GetByUserID>\n"
"</soap:Body>\n"
"</soap:Envelope>\n", candidate
];
NSLog(@"%@",soapMessage);
// Build Our Request
NSURL *url = [NSURL URLWithString:@"http://photoswapper.mick-walker.co.uk/UsersService.asmx"];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];
NSString *msgLength = [NSString stringWithFormat:@"%d", [soapMessage length]];
[theRequest addValue: @"text/xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
[theRequest addValue: @"http://tempuri.org/GetByUserID" forHTTPHeaderField:@"SOAPAction"];
[theRequest addValue: msgLength forHTTPHeaderField:@"Content-Length"];
[theRequest setHTTPMethod:@"POST"];
[theRequest setHTTPBody: [soapMessage dataUsingEncoding:NSUTF8StringEncoding]];
NSError *WSerror;
NSURLResponse *WSresponse;
webData = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&WSresponse error:&WSerror];
xmlParser = [[NSXMLParser alloc] initWithData: webData];
[xmlParser setDelegate: self];
[xmlParser setShouldResolveExternalEntities: YES];
[xmlParser parse];
}
return self;
}
Следуя из комментария Лорента, я попытался осуществить свое собственное решение, я был бы благодарен, если Вы могли бы сообщить мне о каком-либо очевидном gotcha's с этим решением:
Я не полностью уверен, что понимаю, что Вы имеете в виду, я попытался осуществить свое собственное решение. Я был бы благодарен, если Вы могли бы сообщить мне то, что Вы думаете:
- (id) init {
self = [super init];
if(self){
// For simplicity I am going to assume that the 3 possible
// initialation vectors are mutually exclusive.
// i.e if userName is used, then userID and emailAddress
// will always be nil
if(self.userName != nil){
// Initialise object based on username
}
if(self.emailAddress != nil){
// Initialise object based on emailAddress
}
if(self.userID != 0){ // UserID is an NSInteger Type
// Initialise object based on userID
}
}
return self;
}
- (id) initWithUserID:(NSInteger) candidate {
self.userID = candidate;
return [self init];
}
- (id) initWithEmailAddress:(NSString *) candidate {
self.emailAddress = candidate;
return [self init];
}
- (id) initWithUserName:(NSString *) candidate {
self.userName = candidate;
return [self init];
}
С уважением
Назначенное определение инициализатора - здесь . Строгое требование заключается в том, чтобы убедиться, что ваши экземпляры совместимы с любым инициализирующим устройством. Для полной информации смотрите Objective-C Programming Guide: реализация инициализатора хорошо документирована.
Edit 2: Fix typo reported by @NSResponder
Edit:
I think call init after set the member is not robust. У членов могут быть странные значения, которые не пройдут тест на инициализацию.
Лучший способ сделать это - сначала вызвать метод "init" (который установит значения по умолчанию для членов), а затем установить члена. Таким образом, у вас будет одинаковая структура кода для всех инициализаторов:
- (id) init {
self = [super init];
if(self){
self.userID = 0;
self.userName = nil;
self.emailAddress = nil;
}
return self;
}
- (id) initWithUserID:(NSInteger) candidate {
self = [self init];
if(self){
self.userID = candidate;
}
return self;
}
Способ, которым я склонен заниматься подобными вещами, заключается в том, что назначенный инициализатор является методом, который принимает наибольшее количество параметров, а более простые инициализаторы просто посылают более детальные -init сообщения. Например:
// simple initializer
- (id) init
{
return [self initWithWidth: 1.0];
}
// not so simple initializer
- (id) initWithWidth:(float) aWidth
{
return [self initWithWidth:aWidth andColor:nil];
}
// designated initializer. This is the one that subclasses should override.
- (id) initWithWidth: (float) aWidth andColor: (NSColor *) aColor
{
if (self = [super init])
{
self.width = aWidth;
self.color = aColor ? aColor : [[self class] defaultColor];
}
return self;
}