Soru Dizelerin Statik NSArray - Görünüm Denetleyicide nasıl / nerede başlatılacağı


Bir Master-Detay uygulamasında, başlıklı 5 bölümden oluşan bir TableView görüntülemek istiyorum:

  1. Senin hareketin
  2. Onların hareket
  3. Kazanılan Oyunlar
  4. Kayıp Oyunlar
  5. Seçenekler

Bu yüzden, Xcode 5.0.2'de ve MasterViewController.m'de (UITableViewController olan) boş bir Master-Detail uygulaması oluşturuyorum.

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    return _titles[section];
}

Benim sorum Ancak NSArray _titles'i nasıl başlatabilirsiniz?

MasterViewController.m'de çalışıyorum:

#import "MasterViewController.h"
#import "DetailViewController.h"

static NSArray *_titles_1 = @[
    @"Your Move",
    @"Their Move",
    @"Won Games",
    @"Lost Games",
    @"Options"
];

@interface MasterViewController () {
    NSMutableArray *_games;

    NSArray *_titles_2 = @[
                         @"Your Move",
                         @"Their Move",
                         @"Won Games",
                         @"Lost Games",
                         @"Options"
    ];
}
@end

@implementation MasterViewController

- (void)awakeFromNib
{
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
        self.clearsSelectionOnViewWillAppear = NO;
        self.preferredContentSize = CGSizeMake(320.0, 600.0);
    }
    [super awakeFromNib];
}

- (void)viewDidLoad
{
     ....
}

Ama her ikisi de yukarıda sözdizimi hataları veriyor:

enter image description here

GÜNCELLEŞTİRME:

Benim için bu basit soru için birçok öneri var, ama bir iOS / Objective-C newbie olarak emin değilim, hangi çözüm en uygun.

dispatch_once - Çok iş parçacıklı bir uygulamada bir kez bir şey yürütmek için bir çalışma zamanı işlemi değil mi? Bu aşırı mı değil mi? Bir const dizisini başlatmak için bir derleme zamanı çözümü bekliyordum ...

viewDidLoad - Uygulamam arka plan ve ön plan arasında değiştiğinde, const dizilimimi tekrar tekrar başlatmaz mıyım?

Daha iyi ayarlamamalıyım NSArray içinde awakeFromNib (tüm ViewControllers'lar için stroyboard sahneleri kullandığımdan)? Ya da belki initSomething (doğru yöntemdir initWithStyle?)


44
2017-12-12 13:17


Menşei


Init onu viewDidLoad. - duci9y
İmzayı static NSArray* const yerine. Dizinin aşağıdaki cevapta görüldüğü zaman başlatılması için birçok yol vardır. Tembel girişleri severim, ancak bu kullanım davası için gerçekten uygun değil. - Hugo Tunius
Aradığınız şey bir (choke!) Singleton tarzı başlatmadır. Kendi sınıfında olması gerekmez, ancak bu sınıfın bir parçası olabilir. - Hot Licks
@AlexanderFarber iOS uygulamaları çok iş parçacıklıdır ve sınıf yöntemleri birden fazla iş parçacığı tarafından eşzamanlı olarak çağrılabilir, bu yüzden kullanımı daha güvenlidir dispatch_once veya bir çeşit kilitleme. Size birinci elden gelen tecrübeleri anlatabilirim, aksi taktirde crasher hataları için potansiyel çok gerçektir. - jlehr


Cevaplar:


Diziyi döndüren bir sınıf yöntemi yazın.

+ (NSArray *)titles
{
    static NSArray *_titles;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _titles = @[@"Your Move",
                    @"Their Move",
                    @"Won Games",
                    @"Lost Games",
                    @"Options"];
    });
    return _titles;
}

O zaman ihtiyaç duyduğunuz her yerde ona erişebilirsiniz:

NSArray *titles = [[self class] titles];

77
2017-12-12 13:26



Kullanıcı, WHERE'nin bunu nasıl yapacağını sormuyor, nasıl değil. Hiç bir yardım sağlamadınız, kullanıcıların cevapları bir nesneyi bir arayüzde başlatmaya çalışıyor. - Simon McLoughlin
@SimonMcLoughlin OP'den alıntı yaparak, "Ancak sorum Nasıl NSArray _titles init? "[vurgu eklendi] - jlehr
Jlehr ve eğer sorunun geri kalanını okursanız, yukarıda bahsedilen sorun nedeniyle sözdizimi uyarıları aldığını göreceksiniz. Kullanıcı, bir nesneyi bir viewController nesnesinin akışında nasıl başlatacağına dair temel bir anlayış ister. Fuar noktası, çözümünüzü oluşturmanın en iyi yolu olabilir, ancak kullanıcı oldukça net bir şekilde WHERE'yi oluşturmak için bilgi aramaktadır. - Simon McLoughlin
Nesneler derleme zamanında tahsis edilemez, dolayısıyla bu genellikle yaptığımız şeydir. Bunu not et dispatch_once sağlanan blokta kodun sadece uygulamanın ömründe bir kez çalışmasını sağlayan bir Grand Central Dispatch işlevidir. - jlehr
Statik yöntemi çağırmak için tam nitelikli sınıf adını kullanabilirsiniz. [[Self class] başlıkları] yerine sadece [MyClassName başlıkları] diyebilirsiniz; - Brody Robertson


Bunu sınıf yöntemiyle başlatabilirsiniz. + başlatmak

static NSArray *_titles_1;

@implementation MasterViewController
+ (void)initialize {
    _titles_1 = @[
        @"Your Move",
        @"Their Move",
        @"Won Games",
        @"Lost Games",
        @"Options"
    ];
}
@end

12
2017-12-12 13:43



Teşekkürler, ama arama yaptım ve (şaşırtıcı bir şekilde!) Bu yöntemin bir sınıf için bir defadan fazla çağrılabileceğine - bir kalıtımsal sınıfın kendi başına uygulanmadığı anlaşılıyor. + başlatmak yöntem. - Alexander Farber
@AlexanderFarber Ardından _titles_1 öğesinin sıfır olduğunu veya mevcut sınıfın +initialize - Emmanuel
Eğer kontrol edersem nil - Bu olamaz +initialize yöntem bir kez, ancak yanlış sınıf için mi - miras sınıfı için mi çalışıyor? - Alexander Farber
+ initialize, sınıfın kendisi için bir kez ve bunu geçersiz kılan her alt sınıf için bir kez çalışır. Bu yüzden "eğer (self == [MyIntendedClass class])" seçeneğini ilk olarak karşılaştırırsınız. Nil denetimi, senkronizasyonu kullanmak için gerekli kılar çünkü iki alt sınıf farklı iş parçacıklarından başlatılabilir. - gnasher729
@ gnasher729 +initialize Apple dokümantasyonuna göre iş parçacığı güvenlidir: The runtime sends the initialize message to classes in a thread-safe manner. - Emmanuel


Yukarıdaki statik dizininizi bildirmelisiniz @implementation.

static NSArray *titles_1 = nil;

@implementation ...

Ve bunu tanımlayın init veya awakeFromNib veya benzeri başka bir yöntem viewDidLoad, applicationDidFinishLaunching nereye istersen.

- (void)initMethod{ //change the method name accordingly

    if (titles_1 == nil){
        [self setTitles_1:@[ @"Your Move", @"Their Move", @"Won Games", @"Lost Games", @"Options" ]];
    }
}

7
2017-12-12 13:21





Bunun gibi bir şey de yapabilirsiniz:

static NSString * const strings[] = {
        [0] = @"string_1",
        [1] = @"string_2",
        [2] = @"string_3",
        [3] = @"string_4",
        // ...
    };

Bu bir değil NSArray ama sen erişebilirsin NSStrings bunun gibi strings[n] 


7
2018-01-13 20:51



Bazen, her zaman en basit çözüm sadece en etkili olanı değil, en iyisidir ... Obj-C'ye nispeten yeni olmak (7 yıl sonra) hala sözdizimi tarafından ertelenirim, ama oldukça eminim, basit Statik dizinin 25 satırlık kod içermesi gerekmiyordu .. C / C ++ arka planım bunun muhtemelen işe yarayacağını söyledi ... NSString * dayNamesArray [7] = {@ "blah", @ "blah", @ "blah" , @ "blah", @ "blah", @ "blah", @ "ve blah"}; En sağduyu çözümü için size kredi veriyorum ... Teşekkürler! - NpC0mpl3t3


Merak ediyorum, eğer aşağıdakiler iyi bir yol olurdu (kendi sorumu cevaplayarak):

#import "MasterViewController.h"
#import "DetailViewController.h"

static const NSArray *_titles;

@interface MasterViewController () {
    NSMutableArray *_objects;
    NSMutableArray *_yourMove;
    NSMutableArray *_theirMove;
    NSMutableArray *_wonGames;
    NSMutableArray *_lostGames;
    NSMutableArray *_options;
}
@end

@implementation MasterViewController

+ (void)initialize
{
    // do not run for derived classes
    if (self != [MasterViewController class])
        return;

    _titles = @[
        @"Your Move",
        @"Their Move",
        @"Won Games",
        @"Lost Games",
        @"Options"
    ];
}

Bu şekilde const NSArray İhtiyacım olmadan önce ve sağa initalize MasterViewController sınıf). Ve self Çek, bu yöntemin tekrar çalışmasını engeller - bazı kalıtım sınıfları kendi başlarına uygulanmadığında +initialize yöntem.


6
2017-12-13 12:48





Nesneleri bu şekilde başlatamazsınız, bunları yalnızca arayüzlerde beyan edebilirsiniz. Aşağıdakileri yapın:

static NSArray *_titles_2;

@interface MasterViewController () {
    NSMutableArray *_games;
}
@end

@implementation MasterViewController
-(void)viewDidLoad()
{
     _titles_2 = @[
                         @"Your Move",
                         @"Their Move",
                         @"Won Games",
                         @"Lost Games",
                         @"Options"
    ];
}
@end
  • veya viewDidLoad yerine viewcontroller init yöntemini kullanabilirsiniz.

2
2017-12-12 13:21



Bu, her örneğin dizinin kendi kopyasına sahip olacağı anlamına gelir. OP'nin aradığı şeyin bu olduğunu düşünmüyorum. - jlehr
Yeterince adil, bu nokta hala nesneyi arayüzde başlatmaya çalıştığı anlamına gelir, bu onun xcode complier uyarılarını kaldırır, bir statik dizi ile ill edit - Simon McLoughlin
Dikkatlice bakarsanız, OP'nin iki farklı başarısız denemeyi yayınladığını görürsünüz; NSArray. - jlehr
@jlehr - Bu görüntü denetleyicisinin kaç örneğini olacağını düşünüyorsunuz? - Hot Licks
@HotLicks hayır geçerli bir noktaydı, kullanıcı açıkça bir statik dizi tanımladı. Kullanıcı, muhtemelen bunu yapmak için bir yoldan çıkmanın bir sebebi vardı. - Simon McLoughlin


dispatch_once çalışır. Karmaşık durumlarda çalışır ve basit durumlarda çalışır. Bu yüzden tutarlı olmak gerekirse, en iyi şey her durumda onu kullanmaktır. Bu, örneğin tüm sabit dizelerinizi NSLocalizedString () çağrılarıyla değiştirdiğinizde çok daha kolay hale getirir. Kod değişikliği gerekmez.

+ (Void) başlatma işleminde bir şeyler yapmak gerçekten yanlış değildir, ancak gerçekten kullanmadan önce bir sınıfı yapılandırmak istediğim durumlara sahip oldum ve başlatma işlemi herhangi bir olası yapılandırma yönteminin yürütülmeye başlanmadan hemen önce çağrılmasıdır. Ve gerçekten bir sınıf içeriğine sahip olmadığınız durumlar var. dispatch_once her zaman çalışır.


2
2018-02-17 14:21





Objective-C ++ kullanmayı tercih ediyorum, dosya adını değiştir xxx.m için xxx.mmve NSArray'ın başlatılması çalışma zamanında gerçekleşecek

yok hayır  dispatch_once,yok hayır sınıf yöntemi, sadece bir satırda yazınız:

static NSArray *const a = @[@"a",@"b",@"c"];

0
2017-09-06 04:26



Bu kod ile hatayı alırsınız: "Initializer elemanı bir derleme zamanı sabiti değil" - Tiago Mendes