objective-c initialization object-initializers

objective c - Inicializadores mĂșltiples Objective-C



initialization object-initializers (2)

Tengo una pregunta simple sobre la creación de múltiples inicializadores dentro de una clase de object-c. Básicamente tengo una clase que representa una sola fila en mi base de datos (usuarios). Actualmente tengo un inicializador que inicializa la clase en función de los usuarios UserID (que también es la clave principal dentro de la base de datos). Cuando se pasa el UserID, la clase se conectará a un servicio web para analizar los resultados y devolver un objeto inicializado a la fila correspondiente. en la base de datos

Dentro de esta base de datos hay varios campos únicos (nombre de usuario y dirección de correo electrónico), también me gustaría poder inicializar mi objeto en base a estos valores. Pero no estoy seguro de cómo tener más de un inicializador, todo lo que he leído indica que soy libre de tener múltiples inicializadores, siempre que cada uno llame al inicializador designado. Si alguien pudiera ayudarme con esto, sería genial.

Mi código inicializador es el siguiente:

- (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; }

Siguiendo el comentario de Laurent, he intentado implementar mi propia solución, le agradecería que me informara de cualquier problema evidente con esta solución:

No estoy totalmente seguro de que entienda lo que quiere decir, he intentado implementar mi propia solución. Le agradecería que me hiciera saber lo que piensa:

- (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]; }

Saludos


La definición del inicializador designado está here . Es un requisito importante garantizar que sus instancias sean coherentes, independientemente del inicializador que utilice. Para una referencia completa, consulte la here : la implementación del inicializador está bien documentada.

Edit 2: Fix typo reportado por @NSResponder

Editar:

Creo que llamar a init después de establecer el miembro no es confiable. Los miembros pueden tener valores extraños que no pasarán la prueba de inicialización.

Una mejor manera de hacerlo es llamar primero al método "init" (que establecerá los valores predeterminados para los miembros) y luego establecer el miembro. De esta manera, tiene la misma estructura de código para todos sus inicializadores:

- (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; }


La forma en que tiendo a hacer este tipo de cosas es que el inicializador designado sea el método que toma la mayoría de los parámetros, y los inicializadores más simples simplemente envían los mensajes de inicio más detallados. Por ejemplo:

// 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; }