簡體   English   中英

從包含的對象中調用UIViewController方法

[英]Calling UIViewController method from within contained object

假設我有幾個屬於UIViewController的對象(模型)。 當其中一個模型發生更改或執行某些操作時,我希望它通知UIViewController,以便視圖可以立即更新,或者作為響應執行一些動畫。

我該怎么做呢? 特別,

(1.)各個對象如何了解ViewController? 如果我將指向ViewController的指針存儲在每個對象中,那么我將引入一個循環引用,其中ViewController引用引用ViewController的子級。

(2.)即使指針很弱,模型對象本身也不知道ViewController內部的哪個視圖與其自身相對應。 例如,假設有10個視圖和10個模型。 這些模型沒有與視圖耦合(即,每個模型都有一個以10個數組表示的視圖,但是索引並不總是相同的,因為用戶不斷在切換它們,所以盡管模型具有一個穩定索引0 ... 9,表示模型0的視圖可能在索引1處,或者稍后在索引2、3,...,9處),因此,在更新模型時,它需要以某種方式告訴ViewController哪個10個視圖代表它,除非它不知道。 因此,ViewController卻不知道要更新哪個View。

我應該補充一點,我當前的代碼只是給每個模型對象一個指向其對應View的指針,因此它不需要通過ViewController來訪問正確的View並更新其內容。 但這似乎違反了MVC,因此我試圖更正我的代碼,並意識到我不知道在這種特殊情況下如何做。

抱歉,這令人困惑。 如果有任何不清楚的地方,我將更新問題。 編輯:更新了更具體的示例代碼。

@interface ViewController : UIViewController<ProfileViewControllerDelegate>
{
    BattleModel* battle;
}

@property (nonatomic, strong) BattleModel* battle;

@property (nonatomic, weak) NSArray* heroPersons; // Person objects
@property (nonatomic, weak) NSArray* villainPersons; // Person objects

@property (nonatomic, strong) IBOutletCollection(PersonImageView) NSArray* villainImages;
@property (nonatomic, strong) IBOutletCollection(HealthBarView) NSArray* villainHealthBars;

@property (nonatomic, strong) IBOutletCollection(PersonImageView) NSArray* heroImages;
@property (nonatomic, strong) IBOutletCollection(HealthBarView) NSArray* heroHealthBars;

@property (weak, nonatomic) IBOutlet UITextView* reporter;

這描述了ViewController接口。 現在,除了Person對攻擊的反應方式之外,每個Person類還處理Person的修改。

@interface Person : NSObject
{
    __weak Profile* profile;
    __weak PersonImageView* personImg;
    __weak BattleModel* currentBattle;
    Reaction* currentReaction;
}
// Reaction happens in the following methods:
-(BOOL) targetedFoeWithMove:(SelectedMove*)selMove log:(UITextView*)reporter;
-(BOOL) wasTargetedByMove:(SelectedMove*)selMove log:(UITextView*)reporter;
-(void) hitFoeWithMove:(SelectedMove*)selMove log:(UITextView*)reporter;
-(void) wasHitByMove:(SelectedMove*)selMove log:(UITextView*)reporter;

如您所見,我當前違反了MVC,因為將報告者傳遞到模型Person中,並且還傳遞了VC應該處理的personImg的指針。 無論如何,隨着戰斗的進行,會在各種有針對性的命中例行程序中查詢“ Reaction *”,然后在該處進行修改,並通知報告者。 請注意,Person在大型方案UIViewController中如何不占用其對應的PersonView的索引,因此,當currentReaction在某個深層例程中觸發並傳遞數據時,ViewController不知道要更新哪個UIView。 它知道一點(創建Person時),但是heroImages和villainImages數組變化了很多(如果一個Person從英雄轉為反派,即使切換到另一側),所以它出生時的索引不是索引它一定是在反應觸發並需要更新PersonImageView的時候。 這有點煩人,所以我可能需要將數據傳遞回UIViewController,告訴它剛剛對哪個PersonImageView進行了響應(我該怎么做?)。

這是一個示例Reaction,僅用於完整性和幫助您了解系統:

-(void) wasHitByMove:(SelectedMove*)selMove log:(UITextView*)reporter
{
    [self.currentReaction personWasHitByMove:selMove inBattle:self.currentBattle log:reporter];
}

然后根據反應是否相關(反應有多個子類來做不同的事情),通過Person屬性設置器調用“ loseLife:(int)life”之類的修改,這就是我需要報告/動畫的時候被冒充到VC。 現在,錯誤的代碼(錯誤的設計)只是直接將動畫發送給人員,然后是報告程序以通知文本。 我意識到這是一個糟糕的設計,這就是為什么我在這里,但它並不像通過回調告訴VC那樣簡單:“(BOOL)嘿,發生了什么事。” 因為哪個PersonImageView是“我”? ViewController如何在執行戰斗邏輯的自身方法中間知道立即響應回調? 回調如何進行? (Re:委托。因此將委托協議附加到Person,PersonImageView和UIViewController嗎?由於它們都遵循該協議,因此它們可以通過協議方法解釋公共消息嗎?)

我也查看了NSNotification,但發現這樣做太復雜了; 似乎更像是一種被動的Observer類型的事情,在我的應用程序中,當反應觸發時,我需要UIViewController 立即用UITextView文本+ PersonImageView動畫更新屏幕。 從某種意義上說,在反應可以再次觸發之前,必須立即進行動畫處理,因為它可能涉及PersonImageView的回卷,掉落或更改外觀。 這不是實時游戲,但是下一次攻擊將已經排隊,並且在觸發currentReaction之前會短暫出現,因此任何形式的延遲或被動觀察都可能是不好的。

代表們

假設您有一個帶有按鈕的視圖。 給它一個協議:

@protocol MyButtonViewDelegate
@required
- (void)buttonPressed;
@end

現在,帶有按鈕的視圖具有如下屬性:

@property (nonatomic, weak) NSObject<MyButtonViewDelegate> *delegate;

它是對視圖控制器的引用。

帶有按鈕類的視圖將具有與該按鈕相關的類似方法:

- (IBAction)buttonPressed:(id)sender {
    [self.delegate buttonPressed];
}

您的視圖控件符合MyButtonViewDelegate協議,並將其自身設置為視圖的委托。 然后實現方法buttonPressed

- (void)buttonPressed {
    // do whatever you want to do when that button was pressed
}

如果您需要在此方法中傳遞對視圖的引用,也可以這樣做:

@protocol MyViewDelegate
@required
- (void)someMethod:(id)sender;
@end

然后:

- (IBAction)someUserInteractionWithView {
    [self.delegate someMethod:self];
}

然后,委托從協議中實現方法:

- (void)someMethod:(id)sender {
    // sender is a reference to the view which called this method on delegate
}

您可以編寫一個協議方法來發送任意數量的參數。 您甚至可以讓這些方法返回使用的值:

@protocol MyResizableViewProtocol
@required
- (CGRect)newSizeForResizableView:(MyResizableView*)resizableView;
@end

視圖類中的某些內容觸發在委托上調用此方法並請求新的大小。 委托實現此方法:

- (CGRect)newSizeForResizableView:(MyResizableView*)resizableView {
    return CGRectMake(0.0f, 0.0f, 100.0f, 400.0f);
}

可調整大小的視圖使用如下方法:

- (void)timeToResize {
    self.frame = [self.delegate newSizeForResizableView:self];
}

就我而言,了解協議和委托是iOS開發的重要方面之一。

有幾種方法可以做到這一點。 一種方法是通過通知。 當這些有趣的事件發生時,讓您的模型發出通知。 然后,您的視圖控制器可以注冊以接收這些通知並采取相應的措施。

在每個模型中,執行以下操作:

[[NSNotificationCenter defaultCenter] postNotificationName:@"somethingInModel3" object:self];

在視圖控制器中,在initviewDidLoad

[[NSNotificationCenter defaultCenter] addObserver:self 
                                     selector:@selector(handleModel3Event:)        
                                         name:@"somethingInModel3" 
                                       object:nil];

選擇器指定將處理通知的方法。 您需要適當地編寫該方法。

您還需要放入(例如,在視圖控制器中的dealloc中):

[[NSNotificationCenter defaultCenter] removeObserver:self];

包是在Objective-C中實現回調的好方法。 這是Apple文檔的鏈接 Apple已經使用NSOperationQueueNSOperation ,查看動畫以及許多其他方法在所有API上實現了塊。 查看有關 iOS中的通信模式的本文 ,它說明了使用委派,阻止,通知等的正確情況。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM