2016-01-22 28 views
6

C'è un modo per assegnare valori di proprietà a un'istanza di classe anche se non è un parametro nel costruttore di init? Ad esempio, in C# posso fare questo:Creazione di oggetti in un'unica fase e inizializzazione delle proprietà in Swift?

public class Student 
{ 
    public string firstName; 
    public string lastName; 
} 

var student1 = new Student(); 
var student2 = new Student { firstName = "John", lastName = "Doe" }; 

Avviso per student2 posso ancora assegnare i valori durante l'inizializzazione anche se non c'è nessun costruttore della classe.

Se non riesci a trovare nello documentation se puoi fare qualcosa del genere per Swift. In caso contrario, esiste un modo per utilizzare extensions per estendere la classe Student per assegnare valori di proprietà durante l'inizializzazione?

Il motivo per cui sto cercando questo è così posso aggiungere un po 'di casi ad un array senza creare esplicitamente le variabili per ogni istanza studente, in questo modo:

var list = new[] { 
    new Student { firstName = "John", lastName = "Doe" }, 
    new Student { firstName = "Jane", lastName = "Jones" }, 
    new Student { firstName = "Jason", lastName = "Smith" } 
} 

Qualsiasi modo nativo o elegante per raggiungere questo in Swift?

risposta

8

Hai un paio di opzioni a seconda di come si vuole per configurare questo tipo e quale sintassi è più conveniente per te.

È possibile definire un iniziatore conveniente che accetta le proprietà che si desidera impostare. Utile se imposti sempre le stesse proprietà, meno utile se imposti un insieme incoerente di proprietà opzionali.

public class Student 
{ 
    public var firstName:String?; 
    public var lastName:String?; 
} 

extension Student { 
    convenience init(firstName: String, lastName: String) { 
     self.init() 
     self.firstName = firstName 
     self.lastName = lastName 
    } 
} 

Student(firstName: "Any", lastName: "Body") 

È possibile definire un iniziatore di convenienza che accetta un blocco per configurare la nuova istanza.

extension Student { 
    convenience init(_ configure: (Student) -> Void) { 
     self.init() 
     configure(self) 
    } 
} 

Student({ $0.firstName = "Any"; $0.lastName = "Body" }) 

Si potrebbe imitare il metodo di Ruby tap come estensione in modo da poter operare su un oggetto nel bel mezzo di una catena di metodo.

extension Student { 
    func tap(block: (Student) -> Void) -> Self { 
     block(self) 
     return self 
    } 
} 

Student().tap({ $0.firstName = "Any"; $0.lastName = "body"}) 

Se questo ultimo è utile che si potrebbe desiderare di essere in grado di adottare tap su qualsiasi oggetto. Non credo che si può fare automaticamente, ma è possibile definire un implementazione di default per rendere più facile:

protocol Tap: AnyObject {} 

extension Tap { 
    func tap(block: (Self) -> Void) -> Self { 
     block(self) 
     return self 
    } 
} 

extension Student: Tap {} 

Student().tap({ $0.firstName = "Any"; $0.lastName = "body"}) 
+0

Questo è brillante! – TruMan1

4

Se la classe non ha initialiser necessario, è possibile utilizzare un metodo di chiusura per impostare le proprietà degli studenti prima di restituire il nuovo oggetto Student come segue:

public class Student { 
    var firstName = String() 
    var lastName = String() 
} 

let student1 = Student() 
let student2: Student = { 
    let student = Student() 
    student.firstName = "John" 
    student.lastName = "Doe" 
    return student 
}() 

print(student2.firstName) // John 
print(student2.lastName) // Doe 
1

La ragione per cui sto cercando questo è così posso aggiungere un po 'di casi a un [.] array senza creare esplicitamente le variabili per ogni istanza studente

non ho familiarità con C#, ma in Swift, si può fare solo con l'inizializzazione degli oggetti all'interno della dichiarazione di matrice:

var list: [Student] = [ 
    Student(firstName: "John", lastName: "Doe"), 
    Student(firstName: "Jane", lastName: "Jones"), 
    Student(firstName: "Jason", lastName: "Smith") 
] 

Gli altri approcci suggeriti sono tutti ugualmente validi, ma se stai semplicemente cercando di compilare un array senza dichiarare alcuna variabile, Swift lo rende così facile.

+1

La classe Student è fuori dal mio controllo e non posso modificarla. Risiede in un altro quadro. Quindi posso solo ereditarlo o estenderlo. – TruMan1

1

Volevo solo far notare che se la struttura può essere immutabili, si può semplicemente utilizzare un struct piuttosto che un class e si otterrà un inizializzatore implicita gratuitamente:

Basta incollare questo in un parco giochi e cambia struttura in classe e vedrai cosa intendo.

struct Student 
{ 
    var firstName : String? 
    var lastName : String? 
} 

var student = Student(firstName: "Dan", lastName: "Beaulieu") 
+0

Ah ah è fantastico !! Non si rendeva conto che le strutture avevano questo ma non altri tipi. Buono a sapersi!! L'unica cosa è che la classe Student è fuori dal mio controllo seppellita in un'altra libreria, quindi non posso modificare la sua fonte. – TruMan1

1

Questo è solo caramelle sintattico ma io uso un operatore personalizzato per fare questo genere di cose:

infix operator <- { associativity right precedence 90 } 
func <-<T:AnyObject>(var left:T, right:(T)->()) -> T 
{ 
    right(left) 
    return left 
} 

let rgbButtons:[UIButton] = 
    [ 
    UIButton() <- { $0.backgroundColor = UIColor.redColor() }, 
    UIButton() <- { $0.backgroundColor = UIColor.greenColor() }, 
    UIButton() <- { $0.backgroundColor = UIColor.blueColor() } 
    ]