2012-03-22 4 views
27

Robię aplikację, a ja mam klasę z całkiem niezliczonymi właściwościami i zastanawiałem się, czy możliwe było nadanie im domyślnej wartości. Bo jeśli uczynić metodę init to dużo pracy, aby wpisać wszystko, istnieje duża szansa, literówka, a to jest po prostu nieładnie kodowanie ...Objective-C ustaw domyślną wartość dla właściwości

To jak wygląda moja klasa jak:

// Goalkeeping attributes 
@property (nonatomic) int aerialAbility; 
@property (nonatomic) int commandOfArea; 
@property (nonatomic) int communication; 
@property (nonatomic) int eccentricity; 
@property (nonatomic) int handling; 
@property (nonatomic) int kicking; 
@property (nonatomic) int oneOnOnes; 
@property (nonatomic) int reflexes; 
@property (nonatomic) int rushingOut; 
@property (nonatomic) int tendencyToPunch; 
@property (nonatomic) int throwing; 

// Technical attributes 
@property (nonatomic) int corners; 
@property (nonatomic) int crossing; 
@property (nonatomic) int dribbling; 
@property (nonatomic) int finishing; 
@property (nonatomic) int firstTouch; 
@property (nonatomic) int freeKickTaking; 
@property (nonatomic) int heading; 
@property (nonatomic) int longShots; 
@property (nonatomic) int longThrows; 
@property (nonatomic) int marking; 
@property (nonatomic) int passing; 
@property (nonatomic) int penaltyTaking; 
@property (nonatomic) int tackling; 
@property (nonatomic) int technique; 

// Mental attributes 
@property (nonatomic) int aggression; 
@property (nonatomic) int anticipation; 
@property (nonatomic) int bravery; 
@property (nonatomic) int composure; 
@property (nonatomic) int concentration; 
@property (nonatomic) int creativity; 
@property (nonatomic) int decisions; 
@property (nonatomic) int determination; 
@property (nonatomic) int flair; 
@property (nonatomic) int influence; 
@property (nonatomic) int offTheBall; 
@property (nonatomic) int positioning; 
@property (nonatomic) int teamwork; 
@property (nonatomic) int workRate; 

// Physical attributes 
@property (nonatomic) int acceleration; 
@property (nonatomic) int agility; 
@property (nonatomic) int balance; 
@property (nonatomic) int jumping; 
@property (nonatomic) int naturalFitness; 
@property (nonatomic) int pace; 
@property (nonatomic) int stamina; 
@property (nonatomic) int strength; 

Tak więc, w realizacji, robię coś takiego:

@synthesize aerialAbility = _aerialAbility; 

I zastanawiałem się, czy byłoby możliwe, aby to zrobić:

@interface MyClass : NSObject 
@property (nonatomic) int someProperty; 

@end 

@implementation MyClass 
@synthesize someProperty = _someProperty = 10; 
@end 

Wiem, że to nie zadziała, a to w ogóle nie pasuje, ale zastanawiałem się, czy istnieje sposób na zrobienie czegoś takiego.

Podobnie jak w Javie można:

class MyClass 
{ 
private int someProperty = 10; 
public int getSomeProperty(){return someProperty;} 
public void setSomeProperty(int someProperty){this.someProperty = someProperty;} 
} 

Odpowiedz

39

Nigdy nie widziałem takiego zachowania wcześniej, ale jestem prawie pewien, że to, co krok init jest dla alokacji gdy obiekt, który jest ustawienie zmiennych i inicjowanie obiekt.

-(id)init { 
    if (self = [super init]) { 
     self.someProperty = 10; 
    } 
    return self; 
} 

a połączenie to tak:

MyClass* test = [[MyClass alloc] init]; 

Zauważ że można mieć więcej niż jedną funkcję init, który pozwala mieć kilka różnych zestawów wartości domyślnych.

To, co robi @synthesize, mówi prekompilatorowi, że powinien wygenerować kod dla set/get, a nie ustawić wartość właściwości. Wartość "=" mówi prekompromantowi, że pomimo, że nazwa zmiennej i właściwości nie są takie same, powinny one być połączone:

Także jako osobistą opinię (w ogóle nierealizowaną na pytanie), ten obiekt wydaje się być bardzo duży i możesz go w jakiś sposób podzielić lub zaproponować coś innego, może ta klasa może dziedziczyć z kilku innych klas, aby nadać mu różne właściwości, których potrzebuje? sugestia, ponieważ nie wiem, jak wygląda twój drugi kod :)

+1

To prawda - inicjatora jest w porządku miejsce do ustawienia wartości początkowej dla ivar lub własności. Dokładniej, wyznaczony inicjator (inicjator, który wywoła każdy inny inicjator klasy) jest tym, w którym powinieneś ustawić te wartości. – Caleb

+0

Dziękuję za sugestie, jednak staram się unikać wprowadzania ponad 30 zadań w inicjalizatorze, a klasa naprawdę nie może być podzielona (oczywiście, zawsze może, ale to tylko pogorszyłoby mój projekt klasy). –

+0

dlaczego chciałbym uniknąć tego, czego nie dostanę. Do tego celu służy init lub możesz użyć słownika, który i tak musiałbyś skonfigurować w init ... – chikuba

9

Dla tak dużej liczby takich atrybutów byłbym skłonny do przechowywania danych jako słownika, a nie poszczególnych właściwości, a ja zapisz wartości domyślne na liście właściwości NSDictionary obiekty można zainicjować za pomocą prope rty łatwo wymieniają.

Jeśli używasz słownika nie jest do Twoich upodobań, nadal przechowywać wartości domyślne na liście właściwości, a w wyznaczonym inicjalizatorze, pętlibym nad elementami na liście właściwości i stosował je do self przy użyciu klucza. kodowanie wartości. Należy pamiętać, że jest to odpowiednie tylko dla zaufanych danych, a nie danych dostarczanych przez użytkownika, ponieważ w przeciwnym razie może zostać przejęte w celu ustawienia innych właściwości, których się nie spodziewasz.

+1

+1, a słownik będzie łatwiejszy do rozszerzenia i późniejszej zmiany. –

+0

Ale co jeśli chcesz przechowywać właściwości mieszane w słowniku? – To1ne

+0

@ To1ne To nie powinno być problemu. NSDictionary nie wymusza bezpieczeństwa typu. Możesz przechowywać wiele typów obiektów. – mtmurdock

4

Tam nie jest wbudowany w Java podobnego sposobu inicjalizacji syntetyzowane Właściwości lub Ivars w Objective C. Jednakże, skoro twoi właściwości wyglądają niemal identycznie, warto rozważyć ich @dynamic zamiast ich syntezy.

Na pewno trzeba napisać dwie przerażające metody (here is a nice and clean example), ale w zamian uzyskasz jednolity sposób przechowywania swoich obiektów jako obiektów wewnątrz NSMutableDictionary. To otwiera kilka interesujących alternatyw niedostępnych dla zwykłych znaków ivara: możesz odroczyć inicjalizację swoich właściwości, dopóki nie będą potrzebne, możesz podać wartości domyślne dla nie ustawionych właściwości lub możesz zainicjować swoje właściwości "hurtowo", wypełniając słownik słownikiem wartości ich kluczy.

+0

Wygląda interesująco, przyjrzę się temu jutro, dzięki! –

0

Powyższa sugestia słownikowa jest dobra. Ja czasami używane dedykowanych obiektów konfiguracyjnych:

@interface GoalKeepingAttributes 
@property (nonatomic) int agression 
@property (nonatomic) int ... etc 
@end 

@implementation GoalKeepingAttributes 
@end 

itd. W razie potrzeby, ta klasa może mieć metodę init, który ustawia kilka wartości i wartości domyślnych.

Prawdopodobnie możesz użyć również struktury w stylu c, ponieważ są to tylko prymitywy.

To prawda, że ​​jest to jedynie odroczenie problemu, przesuwając inicjalizacji z jednej klasy do klasy config, ale:

  • trzeba by to zrobić ze słownikiem i tak
  • co możliwe komentarz ustawień config
  • największa wygrana: klasa config jest silnie wpisany, który łapie błędy w czasie kompilacji, pozwala na uzupełnianie kodu Xcode

można podzielić w górę konfiguracje do różnych typów (Bramka, Techniczna i Mentalna). Ponownie, to po prostu dzieli problem, ale to może pomóc skupić się na rzeczy.

0

Inną możliwością jest zastąpienie domyślnych pobierających dla właściwości. W plikach pobierających możesz sprawdzić, czy wartości zostały zainicjowane, a jeśli nie, zwrócić wartość domyślną. (To będzie pracować dla niektórych rodzajów własności, ale nie dla innych, jasno - trzeba wartość domyślną, aby być jednym, który wskazuje, że żadna wartość nie została ustalona.)

0
- (id)init 
{ 
    self = [super init]; 
    if (self != nil) { 
     [self commonInit]; 
    } 

    return self; 
} 

- (id)initWithFrame:(CGRect)frame 
{ 
    self = [super initWithFrame:frame]; 
    if (self != nil) { 
     [self commonInit]; 
    } 

    return self; 
} 

-(instancetype)initWithCoder:(NSCoder *)aDecoder { //nib init 
    self = [super initWithCoder:aDecoder]; 
    if (self != nil) { 
     [self commonInit]; 
    } 
    return self; 
} 

Można ustawić wartość domyślną i zrobić domyślnej logiki w commonInit funkcja, jeśli obiekt jest widokiem. Jeśli nie jest to widok, możesz to zrobić w mojej funkcji init.

0

Tak, można przesłonić getter, aby ustawić domyślną wartość przed wprowadzeniem właściwości.

Na przykład, określenie właściwości w pliku .h:

@interface MySegmentedControl : UISegmentedControl 
@property (assign, nonatomic) CGFloat systemFontOfSize; 
@end 

i zastąpić getter i ustawić wartość domyślną w ramach realizacji w .m pliku:

@implementation MySegmentedControl  
-(CGFloat) systemFontOfSize 
{ 
    return _systemFontOfSize ? _systemFontOfSize : 17.0f; 
}  
@end