2013-01-17 16 views
17

मैं राज्य बहाली के साथ चारों ओर घूम रहा हूं। नीचे दिए गए कोड में, UITableViewController की स्क्रॉल स्थिति को पुनर्स्थापित किया जाता है, हालांकि, अगर मैं विस्तार दृश्य (MyViewController के नेविगेशन स्टैक पर एक पुश करना) में टैप करना था, जब ऐप पुनरारंभ होता है, तो यह हमेशा पहले दृश्य पर वापस आता है नेविगेशन स्टैक में नियंत्रक (यानी MyTableViewController)। क्या कोई मुझे सही दृश्य नियंत्रक (यानी MyOtherViewController) में पुनर्स्थापित करने में मदद कर सकता है?UINavigationController राज्य बहाली (स्टोरीबोर्ड के बिना)

AppDelegate.m

- (BOOL)launchWithOptions:(NSDictionary *)launchOptions 
{ 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 
     // Override point for customization after application launch. 


     MyTableViewController *table = [[MyTableViewController alloc] initWithStyle:UITableViewStylePlain]; 
     table.depth = 0; 
     UINavigationController *navCon = [[UINavigationController alloc] initWithRootViewController:table]; 
     navCon.restorationIdentifier = @"navigationController"; 

     self.window.rootViewController = navCon; 

     self.window.backgroundColor = [UIColor whiteColor]; 
     [self.window makeKeyAndVisible]; 

    }); 

    return YES; 
} 

- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    return [self launchWithOptions:launchOptions]; 
} 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    return [self launchWithOptions:launchOptions]; 
} 

MyTableViewController.m

- (id)initWithStyle:(UITableViewStyle)style 
{ 
    self = [super initWithStyle:style]; 
    if(self) 
    { 
     self.restorationIdentifier = @"master"; 
    } 
    return self; 
} 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    self.title = @"Master"; 
    self.tableView.restorationIdentifier = @"masterView"; 
} 

#pragma mark - Table view data source 

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
{ 
    return 5; 
} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 
    return 10; 
} 

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section 
{ 
    return [NSString stringWithFormat:@"Section %d", section]; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    static NSString *CellIdentifier = @"Cell"; 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
    if(!cell) 
    { 
     cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; 
    } 

    cell.textLabel.text = [NSString stringWithFormat:@"%d", indexPath.row]; 

    return cell; 
} 

#pragma mark - Table view delegate 

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    MyOtherViewController *vc = [[MyOtherViewController alloc] initWithNibName:nil bundle:nil]; 
    [self.navigationController pushViewController:vc animated:YES]; 
} 

MyOtherViewController.m

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 
{ 
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 
    if (self) { 
     self.restorationIdentifier = @"detail"; 
    } 
    return self; 
} 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    self.title = @"Detail"; 
    self.view.backgroundColor = [UIColor redColor]; 
    self.view.restorationIdentifier = @"detailView"; 
} 
+0

मुझे मिल गया है मैं आपकी मदद करेगा लगता है कि का पालन करें, लेकिन मैं के बारे में लंबे समय तक (ऑस्ट्रेलिया दिवस) सप्ताहांत के लिए दूर यहां जाने के लिए कर रहा हूँ। यदि आपके पास वापस आने पर स्वीकार्य उत्तर नहीं मिला है तो मैं इसे पोस्ट करूंगा। – CuberChase

+0

हाय एंडी क्या आपने अपनी समस्या का समाधान किया? – Daniel

उत्तर

15

क्योंकि आप कोड में अपना विस्तार दृश्य नियंत्रक बना रहे हैं, और इसे स्टोरीबोर्ड से तुरंत चालू नहीं कर रहे हैं, तो आपको एक बहाली कक्षा को कार्यान्वित करने की आवश्यकता है, इसलिए सिस्टम बहाली प्रक्रिया जानता है कि विस्तार दृश्य नियंत्रक कैसे बनाया जाए।

एक बहाली कक्षा वास्तव में केवल एक कारखाना है जो जानता है कि एक बहाली पथ से एक विशिष्ट दृश्य नियंत्रक कैसे बनाया जाए। आपसे वास्तव में यह एक अलग वर्ग बनाने के लिए की जरूरत नहीं है, हम बस MyOtherViewController में इसे संभाल कर सकते हैं:

MyOtherViewController.h में

, प्रोटोकॉल लागू: UIViewControllerRestoration

फिर जब आप MyOtherViewController.m में restorationID सेट

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 
{ 
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 
    if (self) { 
     self.restorationIdentifier = @"detail"; 
     self.restorationClass = [self class]; //SET THE RESTORATION CLASS 
    } 
    return self; 
} 

फिर आप बहाली कक्षा में इस विधि लागू करने की आवश्यकता (MyOtherViewController.m)

+(UIViewController *) viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder 
{ 
    //At a minimum, just create an instance of the correct class. 
    return [[MyOtherViewController alloc] initWithNibName:nil bundle:nil]; 
} 
:, यह भी बहाली वर्ग सेट

जो आपको पुनर्स्थापन उपप्रणाली को नेविगेशन स्टैक पर विस्तार दृश्य नियंत्रक बनाने और धक्का देने में सक्षम होने तक प्राप्त करता है। (आप शुरू में क्या कहा था।)

उदाहरण को संभालने के लिए राज्य का विस्तार:

कोई वास्तविक अनुप्रयोग में, आप राज्य को बचाने और यह बहाल संभाल दोनों की जरूरत होगी ... मैं निम्नलिखित संपत्ति जोड़ा MyOtherViewController को परिभाषा इस अनुकरण करने के लिए:

@property (nonatomic, strong) NSString *selectedRecordId; 

और मैं भी जो कुछ भी रिकॉर्ड क्रमांक उपयोगकर्ता चयनित करने के लिए विस्तार से शीर्षक सेट करने के MyOtherViewContoller के viewDidLoad विधि संशोधित:

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    // self.title = @"Detail"; 
    self.title = self.selectedRecordId; 
    self.view.backgroundColor = [UIColor redColor]; 
    self.view.restorationIdentifier = @"detailView"; 
} 

उदाहरण के काम करने के लिए, मैं selectedRecordId सेट जब शुरू में MyTableViewController से विस्तार से देखें धक्का: अपने विवरण दृश्य

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    MyOtherViewController *vc = [[MyOtherViewController alloc] initWithNibName:nil bundle:nil]; 
    vc.selectedRecordId = [NSString stringWithFormat:@"Section:%d, Row:%d", indexPath.section, indexPath.row]; 
    [self.navigationController pushViewController:vc animated:YES]; 
} 

अन्य लापता टुकड़ा MyOtherViewController में तरीके हैं, विस्तार से नियंत्रक के राज्य को बचाने के लिए ।

-(void)encodeRestorableStateWithCoder:(NSCoder *)coder 
{ 
    [coder encodeObject:self.selectedRecordId forKey:@"selectedRecordId"]; 
    [super encodeRestorableStateWithCoder:coder]; 
} 

-(void)decodeRestorableStateWithCoder:(NSCoder *)coder 
{ 
    self.selectedRecordId = [coder decodeObjectForKey:@"selectedRecordId"]; 
    [super decodeRestorableStateWithCoder:coder]; 
} 

अब यह वास्तव में अभी तक काफी काम नहीं करता है। ऐसा इसलिए है क्योंकि "ViewDidLoad" विधि को decoreRestorablStateWithCoder विधि से पहले बहाली पर बुलाया जाता है। इसलिए दृश्य प्रदर्शित होने से पहले शीर्षक सेट नहीं किया जाता है। इसे ठीक करने के लिए, हम या तो viewWillAppear में विस्तार से दृश्य नियंत्रक के लिए शीर्षक सेट संभाल:, या हम जब यह इस तरह वर्ग बनाता है राज्य को बहाल करने के viewControllerWithRestorationIdentifierPath विधि को संशोधित कर सकते हैं:

+(UIViewController *) viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder 
{ 
    MyOtherViewController *controller = [[self alloc] initWithNibName:nil bundle:nil]; 
    controller.selectedRecordId = [coder decodeObjectForKey:@"selectedRecordId"]; 
    return controller; 

} 

यह है कि।

कुछ अन्य नोटों ...

मैं अनुमान आप अपने ऐप्स प्रतिनिधि में निम्नलिखित भले ही मैं कोड नहीं देखा था किया था?

-(BOOL) application:(UIApplication *)application shouldSaveApplicationState:(NSCoder *)coder 
{ 
    return YES; 
} 
- (BOOL) application:(UIApplication *)application shouldRestoreApplicationState:(NSCoder *)coder 
{ 
    return YES; 
} 

मैं जब इसे सही ढंग से संरक्षण स्क्रॉल ऑफसेट के साथ सिम्युलेटर में डेमो कोड चलाने की समस्या की का एक सा देखा। यह कभी-कभी मेरे लिए काम करना प्रतीत होता था, लेकिन हर समय नहीं। मुझे संदेह है कि ऐसा इसलिए हो सकता है क्योंकि MyTableViewController की वास्तव में बहाली को पुनर्स्थापना क्लास दृष्टिकोण का भी उपयोग करना चाहिए, क्योंकि यह कोड में तत्काल है। हालांकि मैंने अभी तक कोशिश नहीं की है।

मेरी परीक्षण विधि, ऐप को स्प्रिंगबोर्ड पर लौटकर पृष्ठभूमि में डालना था (ऐप राज्य को सहेजने के लिए आवश्यक था।), फिर ऐप को एक्सकोड के भीतर से क्लीन स्टार्ट अनुकरण करने के लिए फिर से लॉन्च करना था।

+0

आपके उत्तर के लिए धन्यवाद, लेकिन यह काफी नहीं है जो मैं ढूंढ रहा हूं। "आपको राज्य को बचाने और इसे बहाल करने की आवश्यकता होगी": मैं खुद को इस राज्य को संभालना नहीं चाहता - यही वह है जो ऐप्पल के राज्य बहाली तर्क को करना चाहिए (http://developer.apple पर "राज्य संरक्षण" देखें .com/लाइब्रेरी/आईओएस/# दस्तावेज़ीकरण/uikit/संदर्भ/UINavigationController_Class/संदर्भ/संदर्भ.html)। इसके अलावा, आपको बहाली कक्षा प्रदान करने की आवश्यकता नहीं है, UIKit को इसका अनुमान लगाना चाहिए (देखें http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/StatePreservation/StatePreservation.html) – Andy

+0

से लिंक आप पोस्ट: "संरक्षण के दौरान, अपने अनुप्रयोग के लिए जिम्मेदार है:। UIKit बोलने कि यह राज्य के संरक्षण का समर्थन करता है UIKit जो देखने नियंत्रकों और विचारों संरक्षित किया जाना चाहिए बोलने किसी भी संरक्षित वस्तुओं के लिए प्रासंगिक डेटा एन्कोडिंग बहाली के दौरान।। , आपका ऐप इसके लिए ज़िम्मेदार है: UIKit को बताएं कि यह राज्य बहाली का समर्थन करता है। UIKit द्वारा अनुरोध की गई वस्तुओं को प्रदान करना (या बनाना) आपकी संरक्षित वस्तुओं की स्थिति को डीकोड करना और हमें ऑब्जेक्ट को अपने पिछले राज्य में वापस करने के लिए इसे डालना। " -अप्पल केवल इतना अनुमान लगा सकता है। –

+0

उसी लिंक से "उदाहरण के लिए, एक नेविगेशन नियंत्रक अपने नेविगेशन स्टैक पर व्यू कंट्रोलर के क्रम के बारे में जानकारी एन्कोड करता है। फिर यह इस जानकारी का उपयोग बाद में उन दृश्य नियंत्रकों को स्टैक पर अपनी पिछली स्थिति में वापस करने के लिए करता है।" – Andy

0

चूंकि आप इसे कोड में कर रहे हैं और स्टोरीबोर्ड के माध्यम से नहीं कर रहे हैं, इसलिए आपको केवल restorationIdentifier प्रदान करने की आवश्यकता होगी, लेकिन आपको विस्तार से देखने के लिए restorationClass भी प्रदान करना होगा।

आप इसे जिस स्थिति -(UIViewController *)application:(UIApplication *)application viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder में अ-निरुपित छोड़ सकता वस्तु (एक restorationIdentifier लेकिन कोई restorationClass साथ दृश्य नियंत्रक) बनाने के लिए आवेदन प्रतिनिधि को बुलाया जाता है।

निम्नलिखित का प्रयास करें (कृपया ध्यान दें UIViewControllerRestoration प्रोटोकॉल):

@interface MyViewController()<UIViewControllerRestoration> 
@end 

@implementation 

- (id)init 
{ 
    self = [super init]; 
    if (self) { 
     // Custom initialization 
    } 

    if([self respondsToSelector:@selector(restorationIdentifier)]){ 
     self.restorationIdentifier = @"DetailViewController"; 
     self.restorationClass = [self class]; 
    } 
    return self; 
} 

#pragma mark - State restoration 

+ (UIViewController *)viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder *)coder 
{ 
    UIViewController *viewController = [[self alloc] init]; 

    return viewController; 
} 

@end 

भी ध्यान रखें कि यह एक बहुत ही सरल उदाहरण है, आम तौर पर आप एक बहुत अधिक दिलचस्प बातें -viewControllerWithRestorationIdentifierPath:coder:

1

में चल रही हो सकता है अपने कोड के साथ समस्या सिर्फ नेविगेशन नियंत्रक इन दो पंक्तियों

UINavigationController *navCon = [[UINavigationController alloc] initWithRootViewController:table]; 
    navCon.restorationIdentifier = @"navigationController"; 

मैं डॉन है टी पता है क्यों नेविगेशन नियंत्रक कभी भी अपनी बहाली कक्षा नहीं मिलता है। मुझे भी यही समस्या थी। मुझे स्टोरीबोर्ड में अकेले नेविगेशन नियंत्रक स्टैंड बनाने के लिए कुछ वैकल्पिक समाधान मिलते हैं और इसका उपयोग करते हैं।

यहाँ

कोड

UIStoryboard* storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" 
    bundle:nil]; 
UINavigationController* navigationController = [storyboard 
    instantiateViewControllerWithIdentifier: 
    @"UINavigationController"]; 

navigationController.viewControllers = @[myController]; 

यह ठीक काम करेगा।

सिर्फ यह कुछ http://petr-pavlik.squarespace.com/blog/2013/6/16/stare-restoration-without-storyboard