亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

在視圖控制器之間進行通信的最佳方式是什么?

在視圖控制器之間進行通信的最佳方式是什么?

肥皂起泡泡 2019-07-12 16:00:51
在視圖控制器之間進行通信的最佳方式是什么?作為目標c、可可和iPhonedev的新手,我強烈希望充分利用語言和框架。我正在使用的資源之一是斯坦福大學的CS193P課程,這是他們在網絡上留下的。它包括課堂講稿、作業和示例代碼,而且由于這門課程是由Appledev提供的,所以我肯定認為它是“從馬嘴里來的”。班級網站:http:/www.stanford.edu/class/cs193p/cgi-bin/index.php第08課與構建一個基于UINavigationController的應用程序有關,該應用程序有多個UIViewController被推入UINavigationController堆棧。UINavigationController就是這樣工作的。這是合乎邏輯的。但是,幻燈片中有一些關于UIViewController之間通信的嚴厲警告。我要引用這一系列的幻燈片:http:/cs193p.stanford.edu/下載/08-NavigationTabBarControllers.pdf第16/51頁:如何不共享數據全局變量或單變量這包括你的申請委托直接依賴關系降低了代碼的可重用性。更難調試和測試好的。我受夠了。不要盲目地將用于在視圖控制器之間通信的所有方法拋到應用程序委托中,并在app委托方法中引用viewController實例。還不錯。再往前看,這張幻燈片告訴我們應做。第18/51頁:數據流的最佳實踐弄清楚一點兒沒錯需要傳達什么定義輸入參數用于視圖控制器為了恢復層次結構,使用松耦合為觀察者定義一個通用接口(如委托)這張幻燈片之后是一張看上去像是保持式幻燈片的幻燈片,講師隨后用UIImagePickerController的例子演示了最佳實踐。我希望錄影帶能提供!好吧那么.??峙挛业膐bjc-fu沒那么強壯。我也有點困惑,最后一行在上面的報價。我一直在谷歌上搜索這方面的內容,我找到了一篇似乎不錯的文章,討論了各種觀察/通知技術的方法:http:/cocoawithlove.com/2008/06/5方法#5甚至指示委托為一種方法!除了.。對象一次只能設置一個委托。那么,當我有多個視圖控制器通信時,我該怎么辦呢?好吧,那是密謀團伙。我知道我可以很容易地在app委托中使用我的通信方法,通過引用我的appagent中的多個視圖控制器實例,但是我想做這樣的事情右(邊),正確的方式,道路。請回答以下問題,幫助我“做正確的事情”:當我試圖在UINavigationController堆棧上推送一個新的視圖控制器時,誰應該做這件事。哪一個類/文件在我的代碼中是正確的位置嗎?當我想影響我的UIViewController中的某個數據(一個IPAR的值)時,我在異類UIViewController,做這件事的“正確”方法是什么?假設我們一次只能在一個對象中設置一個委托,那么當講師說的時候,實現是什么樣子的呢?“為觀察員定義通用接口(如委托)”..如果可能的話,偽代碼示例在這里非常有用。
查看完整描述

3 回答

?
慕哥9229398

TA貢獻1877條經驗 獲得超6個贊

這些都是很好的問題,很高興看到你正在做這項研究,并且似乎關心的是如何“做好”,而不是僅僅把它整合在一起。

第一,我同意前面的答案,這些答案側重于在適當的時候將數據放在模型對象中的重要性(根據MVC設計模式)。通常,您希望避免將狀態信息放入控制器中,除非它是嚴格的“表示”數據。

第二,有關如何以編程方式將控制器推送到導航控制器的示例,請參閱斯坦福演示文稿第10頁。有關如何使用InterfaceBuilder進行“可視化”操作的示例,請參閱本教程.

第三也許最重要的是,請注意,如果您在“依賴注入”設計模式中考慮到“最佳實踐”,那么在斯坦福演示中提到的“最佳實踐”要容易得多。簡而言之,這意味著您的控制器不應該“查找”它執行其工作所需的對象(例如,引用全局變量)。相反,您應該始終將這些依賴項“注入”到控制器中(即,通過方法傳遞它需要的對象)。

如果遵循依賴注入模式,則控制器將是模塊化和可重用的。如果你想一想斯坦福的演講者們來自哪里(比如,作為蘋果員工,他們的工作就是構建易于重用的類),可重用性和模塊化是高度優先考慮的問題。他們提到的共享數據的所有最佳實踐都是依賴注入的一部分。

這就是我回答的要點。我將包括一個示例,說明如何在下面的控制器中使用依賴注入模式,以防有幫助。

在視圖控制器中使用依賴項注入的示例

假設您正在構建一個屏幕,其中列出了幾本書。用戶可以選擇他/她想買的書,然后點擊“結賬”按鈕進入結賬屏幕。

為此,您可以創建一個BookPickerViewController類來控制和顯示GUI/View對象。它將從哪里得到所有的書籍數據?假設它依賴于一個BookWarehouse對象?,F在,您的控制器基本上是在模型對象(BookWarehouse)和GUI/View對象之間代理數據。換句話說,BookPickerViewController依賴于BookWarehouse對象。

別這么做:

@implementation BookPickerViewController-(void) doSomething {
   // I need to do something with the BookWarehouse so I'm going to look it up
   // using the BookWarehouse class method (comparable to a global variable)
   BookWarehouse *warehouse = [BookWarehouse getSingleton];
   ...}

相反,應該像這樣注入依賴關系:

@implementation BookPickerViewController-(void) initWithWarehouse: (BookWarehouse*)warehouse {
   // myBookWarehouse is an instance variable
   myBookWarehouse = warehouse;
   [myBookWarehouse retain];}-(void) doSomething {
   // I need to do something with the BookWarehouse object which was 
   // injected for me
   [myBookWarehouse listBooks];
   ...}

當蘋果公司的人在談論使用委托模式“在層次結構上進行溝通”時,他們仍然在談論依賴注入。在本例中,一旦用戶選擇了他/她的書并準備退房,BookPickerViewController應該做些什么?這不是它的工作。它應該將工作委托給其他對象,這意味著它依賴于另一個對象。因此,我們可以修改BookPickerViewController init方法如下:

@implementation BookPickerViewController-(void) initWithWarehouse:    (BookWarehouse*)warehouse 
        andCheckoutController:(CheckoutController*)checkoutController 
{
   myBookWarehouse = warehouse;
   myCheckoutController = checkoutController;}-(void) handleCheckout {
   // We've collected the user's book picks in a "bookPicks" variable
   [myCheckoutController handleCheckout: bookPicks];
   ...}

所有這些的最終結果是,您可以給我您的BookPickerViewController類(以及相關的GUI/視圖對象),我可以在我自己的應用程序中輕松地使用它,假設BookWarehouse和CheckoutController是我可以實現的通用接口(即協議):

@interface MyBookWarehouse : NSObject <BookWarehouse> { ... } @end@implementation MyBookWarehouse { ... } 
@end@interface MyCheckoutController : NSObject <CheckoutController> { ... } @end@implementation MyCheckoutController { ... } 
@end...-(void) applicationDidFinishLoading {
   MyBookWarehouse *myWarehouse = [[MyBookWarehouse alloc]init];
   MyCheckoutController *myCheckout = [[MyCheckoutController alloc]init];

   BookPickerViewController *bookPicker = [[BookPickerViewController alloc] 
                                         initWithWarehouse:myWarehouse 
                                         andCheckoutController:myCheckout];
   ...
   [window addSubview:[bookPicker view]];
   [window makeKeyAndVisible];}

最后,您的BookPickerController不僅可重用,而且更易于測試。

-(void) testBookPickerController {
   MockBookWarehouse *myWarehouse = [[MockBookWarehouse alloc]init];
   MockCheckoutController *myCheckout = [[MockCheckoutController alloc]init];

   BookPickerViewController *bookPicker = [[BookPickerViewController alloc] initWithWarehouse:myWarehouse andCheckoutController:myCheckout];
   ...
   [bookPicker handleCheckout];

   // Do stuff to verify that BookPickerViewController correctly called
   // MockCheckoutController's handleCheckout: method and passed it a valid
   // list of books
   ...}


查看完整回答
反對 回復 2019-07-12
?
慕尼黑的夜晚無繁華

TA貢獻1864條經驗 獲得超6個贊

這類事情總是品位問題。

話雖如此,我總是更喜歡通過模型對象進行協調(#2)。頂層視圖控制器加載或創建所需的模型,每個視圖控制器在其子控制器中設置屬性,以告訴它們需要使用哪些模型對象。大多數更改都是通過使用NSNotificationCenter在層次結構上進行通信的;觸發通知通常是內置到模型本身的。

例如,假設我有一個帶有帳戶和事務的應用程序。我還有一個AccountListController、一個AccountController(它用一個“顯示所有事務”按鈕顯示帳戶摘要)、一個TransactionListController和一個TransactionController。AccountListController加載所有帳戶的列表并顯示它們。當您點擊列表項時,它會設置其AccountController的.Account屬性,并將AccountController推到堆棧上。當您點擊“顯示所有事務”按鈕時,AccountController加載事務列表,將其放入其TransactionListController的.Transes屬性中,并將TransactionListController推送到堆棧上,依此類推。

例如,如果TransactionController編輯了事務,它就會對其事務對象進行更改,然后調用它的‘Save’方法。“保存”發送一個TransactionChangedNotification。當事務更改時,任何其他需要刷新自身的控制器都會觀察通知并更新自身。據推測,TransactionListController會這樣做;AccountController和AccountListController可能會這樣做,這取決于它們試圖做什么。

對于#1,在我早期的應用程序中,我有某種顯示模型:With NavigationController:方法在子控制器中,它會設置東西并將控制器推到堆棧上。但是,隨著我對SDK的使用變得更加舒服,我已經遠離了它,現在我通常讓父母推著孩子。

對于#3,請考慮下面的示例。在這里,我們使用兩個控制器,AmountEditor和TextEditor來編輯事務的兩個屬性。編輯器不應該實際保存正在編輯的事務,因為用戶可以決定放棄事務。因此,相反,他們都將父控制器作為委托,并對其調用一個方法,說明是否更改了任何內容。

@class Editor;@protocol EditorDelegate// called when you're finished.  updated = YES for 'save' button, NO for 'cancel'- (void)editor:
(Editor*)editor finishedEditingModel:(id)model updated:(BOOL)updated;  @end// this is an abstract class@interface Editor : 
UIViewController {
    id model;
    id <EditorDelegate> delegate;}@property (retain) Model * model;@property (assign) id <EditorDelegate> delegate;...define 
    methods here...@end@interface AmountEditor : Editor...define interface here...@end@interface TextEditor : Editor...define 
    interface here...@end// TransactionController shows the transaction's details in a table view@interface TransactionController : 
    UITableViewController <EditorDelegate> {
    AmountEditor * amountEditor;
    TextEditor * textEditor;
    Transaction * transaction;}...properties and methods here...@end

現在有幾種來自TransactionController的方法:

- (void)viewDidLoad {
    amountEditor.delegate = self;
    textEditor.delegate = self;}- (void)editAmount {
    amountEditor.model = self.transaction;
    [self.navigationController pushViewController:amountEditor animated:YES];}- (void)editNote {
    textEditor.model = self.transaction;
    [self.navigationController pushViewController:textEditor animated:YES];}- (void)editor:(Editor*)editor finishedEditingModel:
    (id)model updated:(BOOL)updated {
    if(updated) {
        [self.tableView reloadData];
    }

    [self.navigationController popViewControllerAnimated:YES];}

需要注意的是,我們已經定義了一個通用協議,編輯可以使用該協議與其擁有的控制器進行通信。通過這樣做,我們可以在應用程序的另一部分重用編輯器。(或許賬戶也可以有筆記。)當然,EditorDelegate協議可以包含多個方法;在這種情況下,這是唯一必要的方法。


查看完整回答
反對 回復 2019-07-12
?
侃侃無極

TA貢獻2051條經驗 獲得超10個贊

我看到你的問題了.。

發生的事情是有人混淆了MVC架構的概念。

MVC有三個部分.。模型、視圖和控制器。說明的問題似乎把其中兩個問題合二為一,沒有充分的理由。視圖和控制器是獨立的邏輯片段。

所以.。您不希望有多個視圖控制器。

您希望擁有多個視圖,以及在它們之間進行選擇的控制器。(如果您有多個應用程序,也可以有多個控制器)

意見不應作出決定。控制器應該這樣做。因此,任務和邏輯的分離,以及讓你的生活變得更容易的方法。

所以.。確保你的觀點能做到這一點,給出一個很好的數據。讓控制器決定如何處理數據,以及使用哪個視圖。

(當我們談論數據時,我們談論的是模型.一種很好的存儲、訪問、修改的標準方式。另一個獨立的邏輯,我們可以把它打包,然后忘掉)


查看完整回答
反對 回復 2019-07-12
  • 3 回答
  • 0 關注
  • 477 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號