首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

iOS 兩個 ViewController 之間 Delegate 傳值失敗:正確設定代理對象

     編輯:程式設計綜合問答

在「排行榜選單」(MenuVC) 推入「遊戲」(GameVC) 時,GameVC 需透過 Delegate 將最高分回傳 MenuVC 更新。常見錯誤:在 viewDidLoad 中 [[ViewController alloc] init] 建立新實例設定 delegate,而非設定給正在顯示的實例。

錯誤程式碼

// MenuVC.m
- (void)viewDidLoad {
    [super viewDidLoad];
    GameVC *vc = [[GameVC alloc] init]; // 錯誤:建立新實例,非即將呈現的那個
    vc.delegateHighScore = self;
}

// 呈現時 (如按鈕點擊)
- (IBAction)startGame:(id)sender {
    GameVC *vc = [[GameVC alloc] init]; // 另一個新實例
    [self presentViewController:vc animated:YES completion:nil];
    // 真正呈現的 vc 沒有設定 delegate!
}

正確做法:在呈現前設定 Delegate

// MenuVC.m
- (IBAction)startGame:(id)sender {
    GameVC *gameVC = [[GameVC alloc] init]; // 或從 Storyboard 實例化
    gameVC.delegateHighScore = self;        // 關鍵:設定給即將呈現的實例
    [self presentViewController:gameVC animated:YES completion:nil];
}

// 若使用 Storyboard + Segue
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"ShowGame"]) {
        GameVC *gameVC = (GameVC *)segue.destinationViewController;
        gameVC.delegateHighScore = self; // 在 prepareForSegue 設定
    }
}

GameVC 協定定義與回呼

// GameVC.h
@protocol HighScoreDelegate 
- (void)updateHighScore:(NSInteger)score;
@end

@interface GameVC : UIViewController
@property (nonatomic, weak) id delegateHighScore;
@property (nonatomic, assign) NSInteger score;
@end

// GameVC.m
- (void)gameOver {
    [self.delegateHighScore updateHighScore:self.score]; // 回呼
    
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Game Over"
                                                    message:[NSString stringWithFormat:@"Score: %ld", (long)self.score]
                                                   delegate:self
                                          cancelButtonTitle:@"Main Menu"
                                          otherButtonTitles:@"Restart", nil];
    [alert show];
}

// AlertView 點擊處理 (若需回主選單)
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    if (buttonIndex == 0) {
        [self dismissViewControllerAnimated:YES completion:nil]; // 回主選單
    } else {
        [self restartGame];
    }
}

核心原則

  1. Delegate 必須設定給「正在使用/即將呈現」的實例,而非隨意 alloc/init 的新實例。
  2. Storyboard 專案:在 prepareForSegue: 設定。
  3. 純程式碼專案:在 presentViewController: 前設定。
  4. Delegate 屬性必須標記 weak 避免循環保留。

替代方案:Unwind Segue (Storyboard 專用)

若僅需從子頁面返回資料給父頁面,可使用 Unwind Segue 簡化流程,無需手寫 Delegate 協定。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved