![](/img/trans.png)
[英]calling a parent UIViewController method from a child 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];
在視圖控制器中,在init
或viewDidLoad
:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleModel3Event:)
name:@"somethingInModel3"
object:nil];
選擇器指定將處理通知的方法。 您需要適當地編寫該方法。
您還需要放入(例如,在視圖控制器中的dealloc
中):
[[NSNotificationCenter defaultCenter] removeObserver:self];
包是在Objective-C中實現回調的好方法。 這是Apple文檔的鏈接 。 Apple已經使用NSOperationQueue
, NSOperation
,查看動畫以及許多其他方法在所有API上實現了塊。 查看有關 iOS中的通信模式的本文 ,它說明了使用委派,阻止,通知等的正確情況。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.