सवाल तारों के स्टेटिक एनएसएआरएआरई - एक व्यू कंट्रोलर में कैसे / कहां प्रारंभ करना है


एक मास्टर-विस्तार ऐप में मैं शीर्षक वाले 5 अनुभागों के साथ एक टेबल व्यू प्रदर्शित करना चाहता हूं:

  1. तुम्हारी चाल
  2. उनका कदम
  3. जीत खेल
  4. खोया खेल
  5. विकल्प

तो मैं एक्सकोड 5.0.2 में एक खाली मास्टर-विस्तार ऐप बना देता हूं और फिर अपने मास्टर व्यू कंट्रोलर.एम (जो एक UITableViewController है) में मैं विधि को लागू करने की कोशिश कर रहा हूं:

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

मेरा प्रश्न हालांकि एनएसएआरएआरए _ टाइटल को कैसे लगाया जाए?

मैं MasterViewController.m में कोशिश कर रहा हूँ:

#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
{
     ....
}

लेकिन दोनों ऊपर की कोशिश करता है मुझे वाक्यविन्यास त्रुटियां देते हैं:

enter image description here

अद्यतन करें:

मेरे आश्चर्य के लिए इस सरल प्रश्न के लिए कई सुझाव हैं, लेकिन आईओएस / उद्देश्य-सी नौसिखिया के रूप में मुझे यकीन नहीं है कि कौन सा समाधान सबसे उपयुक्त है।

dispatch_once - क्या यह बहु-थ्रेडेड ऐप में एक बार निष्पादित करने के लिए रनटाइम ऑपरेशन नहीं है? क्या यह यहां अधिक नहीं है? मैं एक कॉन्स एरे शुरू करने के लिए एक संकलन समय समाधान की उम्मीद कर रहा था ...

viewDidLoad - जब मेरा ऐप पृष्ठभूमि और अग्रभूमि के बीच बदलता है, तो क्या यह अनावश्यक बार-बार मेरे कॉन्स सरणी को शुरू नहीं करेगा?

क्या मुझे बेहतर सेट नहीं करना चाहिए NSArray में awakeFromNib (चूंकि मैं अपने सभी व्यू कंट्रोलर के लिए स्ट्रायबोर्ड दृश्यों का उपयोग करता हूं)? या शायद अंदर initSomething (सही विधि है initWithStyle?)


44
2017-12-12 13:17


मूल


इसमें प्रवेश करें viewDidLoad। - duci9y
आपको हस्ताक्षर बदलना चाहिए static NSArray* const बजाय। नीचे दिए गए उत्तर में दिखाई देने वाले सरणी को प्रारंभ करने के लिए हल करने के कई तरीके हैं। मुझे आलसी inits पसंद है, लेकिन यह इस उपयोग के मामले के लिए वास्तव में उपयुक्त नहीं है। - Hugo Tunius
जो आप खोज रहे हैं वह है (चोक!) सिंगलटन-स्टाइल प्रारंभिकरण। इसे अपनी कक्षा में होने की आवश्यकता नहीं है, हालांकि, यह इस वर्ग का हिस्सा हो सकता है। - Hot Licks
@AlexanderFarber आईओएस ऐप्स बहु-थ्रेडेड हैं, और क्लास विधियों को कई धागे द्वारा समवर्ती रूप से कहा जा सकता है, इसलिए इसका उपयोग सुरक्षित है dispatch_once या लॉकिंग के कुछ रूप। मैं आपको पहले हाथ के अनुभव से बता सकता हूं कि अन्यथा क्रैशर बग की संभावना बहुत असली है। - jlehr


जवाब:


एक वर्ग विधि लिखें जो सरणी देता है।

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

फिर आप इसे कहीं भी एक्सेस कर सकते हैं:

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

77
2017-12-12 13:26



उपयोगकर्ता यह कहने के लिए कह रहा है कि कैसे नहीं। आपने कोई मदद नहीं दी है, उपयोगकर्ता के जवाब से पता चलता है कि वह किसी ऑब्जेक्ट में किसी ऑब्जेक्ट को तुरंत चालू करने का प्रयास कर रहा है - Simon McLoughlin
@ सिमॉनएमसीलोफिन ओपी का हवाला देते हुए, "मेरा सवाल हालांकि है किस तरह NSArray _titles init करने के लिए? "[जोर जोड़ा] - jlehr
@jlehr और यदि आप शेष प्रश्न पढ़ते हैं तो आप देखेंगे कि उपर्युक्त मुद्दे के कारण उन्हें वाक्यविन्यास चेतावनी मिल रही है। उपयोगकर्ता दृश्य नियंत्रक ऑब्जेक्ट के प्रवाह में ऑब्जेक्ट को तुरंत चालू करने के बारे में मूलभूत समझ के लिए कह रहा है। उचित बिंदु यह है कि आपका समाधान इसे बनाने का सबसे अच्छा तरीका हो सकता है, लेकिन उपयोगकर्ता इसे स्पष्ट रूप से जानकारी के लिए देख रहा है कि इसे कहां बनाना है - Simon McLoughlin
संकलन समय पर वस्तुओं को आवंटित नहीं किया जा सकता है, इसलिए यह आमतौर पर हम करते हैं। ध्यान दें कि dispatch_once एक ग्रैंड सेंट्रल डिस्पैच फ़ंक्शन है जो सुनिश्चित करता है कि प्रदान किए गए ब्लॉक में कोड केवल ऐप के जीवनकाल में ही चलाया जाता है। - jlehr
आप स्थिर विधि को कॉल करने के लिए पूरी तरह योग्य क्लास नाम का उपयोग कर सकते हैं। [[स्वयं वर्ग] खिताब के बजाय] आप बस [MyClassName शीर्षक] को कॉल कर सकते हैं; - Brody Robertson


आप कक्षा विधि में इसे शामिल कर सकते हैं + प्रारंभ

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



धन्यवाद, लेकिन मैंने खोज की है और ऐसा लगता है (आश्चर्य की बात है!) कि इस विधि को कक्षा के लिए एक से अधिक बार बुलाया जा सकता है - जब एक विरासत वर्ग स्वयं लागू नहीं होता है + प्रारंभ तरीका। - Alexander Farber
@AlexanderFarber फिर जांचें कि _titles_1 शून्य है या वर्तमान कक्षा में है +initialize - Emmanuel
अगर मैं जांच करता हूं nil - ऐसा नहीं हो सकता है कि +initialize विधि एक बार चलता है, लेकिन एक गलत वर्ग के लिए - विरासत वर्ग के लिए? - Alexander Farber
+ कक्षा के लिए एक बार दौड़ना शुरू करें, और एक बार प्रत्येक उपclass के लिए जो इसे ओवरराइड नहीं करता है। यही कारण है कि आप "अगर (self == [MyIntendedClass क्लास])" की तुलना करें। शून्य के लिए जांच सिंक्रनाइज़ेशन का उपयोग करने के लिए आवश्यक बनाता है क्योंकि दो subclasses विभिन्न धागे से शुरू किया जा सकता है। - gnasher729
@ gnasher729 +initialize ऐप्पल दस्तावेज के अनुसार, थ्रेड सुरक्षित है: The runtime sends the initialize message to classes in a thread-safe manner. - Emmanuel


आपको उपरोक्त अपनी स्थिर सरणी घोषित करनी चाहिए @implementation

static NSArray *titles_1 = nil;

@implementation ...

और इसे परिभाषित करें init या awakeFromNib या किसी अन्य विधि की तरह viewDidLoad, applicationDidFinishLaunching जहाँ भी आप चाहते हैं।

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





आप ऐसा कुछ भी कर सकते हैं:

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

यह एक नहीं है NSArray लेकिन आप पहुंच सकते हैं NSStrings इस तरह strings[n] 


7
2018-01-13 20:51



कभी-कभी, सबसे सरल समाधान सबसे प्रभावी नहीं है, बल्कि सबसे अच्छा ... Obj-C (7 साल अब) के लिए अपेक्षाकृत नया होने के नाते मुझे अभी भी वाक्यविन्यास से हटा दिया गया है, लेकिन मुझे पूरा यकीन था, एक साधारण स्थिर सरणी को कोड की 25 लाइनों को शामिल करने की आवश्यकता नहीं थी .. मेरी सी / सी ++ पृष्ठभूमि ने मुझे बताया कि यह शायद काम करेगा ... NSString * dayNamesArray [7] = {@ "blah", @ "blah", @ "blah" , @ "ब्लाह", @ "ब्लाह", @ "ब्लाह", @ "और ब्लाह"}; मैं आपको सबसे सामान्य ज्ञान समाधान के लिए क्रेडिट देता हूं ... धन्यवाद! - NpC0mpl3t3


मुझे आश्चर्य है, अगर निम्नलिखित एक अच्छा तरीका होगा (मेरे अपने प्रश्न का उत्तर दें):

#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"
    ];
}

इस तरह से const NSArray मुझे इसकी आवश्यकता होने से पहले एक बार और सही initalized है (में MasterViewController कक्षा)। और यह self चेक इस विधि को फिर से चलाने से रोकता है - जब कुछ विरासत वर्ग स्वयं को लागू नहीं करता है +initialize तरीका।


6
2017-12-13 12:48





आप इस तरह से वस्तुओं को तुरंत चालू नहीं कर सकते हैं, आप केवल उन्हें इंटरफेस में घोषित कर सकते हैं। निम्न कार्य करें:

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
  • या इसी तरह आप viewDidLoad के बजाय viewcontroller init विधि का उपयोग कर सकते हैं

2
2017-12-12 13:21



इसका मतलब यह होगा कि प्रत्येक इंस्टेंस में सरणी की अपनी प्रति होगी। मुझे नहीं लगता कि ओपी क्या ढूंढ रहा था। - jlehr
काफी उचित है, बिंदु अभी भी खड़ा है कि वह इंटरफ़ेस में ऑब्जेक्ट को तुरंत चालू करने का प्रयास कर रहा है, इससे उसकी एक्सकोड शिकायत चेतावनियां निकल जाएंगी, एक स्थिर सरणी के साथ बीमार संपादन होगा - Simon McLoughlin
यदि आप ध्यान से देखते हैं, तो आप देखेंगे कि ओपी ने दो अलग-अलग असफल प्रयासों को पोस्ट किया था, जिनमें से पहला वैश्विक स्थिरता आरंभ करने का प्रयास था NSArray। - jlehr
@jlehr - इस दृश्य नियंत्रक के कितने उदाहरण आपको लगता है कि ऐसा होने जा रहे हैं? - Hot Licks
@HotLicks नहीं जो एक वैध बिंदु था, उपयोगकर्ता ने एक स्थिर सरणी को स्पष्ट रूप से परिभाषित किया था। संभवतः उपयोगकर्ता को ऐसा करने का कोई कारण नहीं था - Simon McLoughlin


dispatch_once काम करता है। यह जटिल मामलों में काम करता है, और यह सरल मामलों में काम करता है। तो सुसंगत होने के लिए, सभी मामलों में इसका उपयोग करना सबसे अच्छी बात है। यह उदाहरण के लिए बहुत आसान बनाता है जब आप अपने सभी निरंतर तारों को NSLocalizedString () पर कॉल के साथ प्रतिस्थापित करते हैं। कोई कोड परिवर्तन की आवश्यकता नहीं है।

शुरुआती + (शून्य) में चीजों को करना वास्तव में गलत नहीं है, लेकिन मेरे पास ऐसी परिस्थितियां हैं जहां मैं वास्तव में इसका उपयोग करने से पहले कक्षा को कॉन्फ़िगर करना चाहता था, और प्रारंभिक रूप से किसी भी संभावित कॉन्फ़िगरेशन विधि को निष्पादित करना शुरू करने से पहले ही शुरू किया जाता है। और ऐसी स्थितियां हैं जहां आपके पास वास्तव में कक्षा संदर्भ नहीं है। dispatch_once हमेशा काम करेगा।


2
2018-02-17 14:21