如何解决仍然为零的委托
Posted
技术标签:
【中文标题】如何解决仍然为零的委托【英文标题】:How to solve a delegate that is still nil 【发布时间】:2012-04-23 06:02:47 【问题描述】:我关心我的 4 个视图控制器。第一个是 CardWalletViewController,它是一个表格视图,由用户创建的卡片对象填充(卡片创建是可以的,所以我不会发布有关的代码)。现在,鉴于这个表格视图已经填充了卡片对象,一旦用户点击一个单元格,另一个名为 CardDetailsViewController 的视图控制器就会出现。这将显示卡的当前积分以及特权。请注意,当前点通过 UILabel 显示,并且特权是表格视图的单元格。此表视图的单元格值(特权)是静态类型的,来自 NSDictionary,然后存储在 NSArray 中(用于单元格的文本显示目的)。现在,当我点击一个福利时,PerksDetailsViewController 会出现。这包含显示 perk 名称和所需点数的 UILabels。这些 UILabels 值来自以前的 ViewController。此外,PerksDetailsVC 有一个名为兑换的按钮。单击该按钮后,我将进入另一个视图控制器 BarCodeViewController,它负责计算。
现在我关心的是如何通过选定的卡片,以及与选定的特权相对应的点数。我已经使用委托来执行此操作,但似乎我的委托对象没有被设置。
下面是我当前的代码。
CardWalletViewController.h
#import <UIKit/UIKit.h>
#import "Card.h"
@class CardWalletViewController;
@protocol CardWalletDelegate <NSObject>
-(void)cardWalletViewController: (CardWalletViewController *)sender
withCurrentCard: (Card *) currentCard;
@end
@interface CardWalletViewController : UITableViewController
@property (nonatomic, strong) NSMutableArray *myWallet;
@property (nonatomic, weak) id <CardWalletDelegate> delegate;
@end
CardWalletViewController.m
#import "CardWalletViewController.h"
#import "AddCardViewController.h"
#import "Card.h"
#import "CardDetailsViewController.h"
@interface CardWalletViewController ()
@end
@implementation CardWalletViewController
@synthesize delegate = _delegate;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
Card *cardDummy = [self.myWallet objectAtIndex:indexPath.row]; //myWallet is an Array where the table cell's values come from
cell.textLabel.text = cardDummy.name;
cell.detailTextLabel.text = [NSString stringWithFormat:@"%@", cardDummy.points];
return cell;
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
//this method is responsible for showing the details of a selected card
CardDetailsViewController *details = [self.storyboard instantiateViewControllerWithIdentifier:@"cardDetails"];
Card *selectedCard = [self.myWallet objectAtIndex:indexPath.row]; // I want this selected card to be accessible until the user clicks another card or during end of program.
details.myPoints = [NSString stringWithFormat:@"%@", selectedCard.points];
[self.navigationController pushViewController:details animated:YES];
[self.delegate cardWalletViewController:self withCurrentCard:selectedCard];
//checking purposes
if (!self.delegate)
NSLog(@"delegate is nil");
CardDetailsViewController.m
#import "CardDetailsViewController.h"
#import "PerksDetailsViewController.h"
#import "Card.h"
@interface CardDetailsViewController ()
@end
@implementation CardDetailsViewController
@synthesize pointsLabel = _pointsLabel;
@synthesize myPoints = _myPoints;
@synthesize perks = _perks;
@synthesize datasource = _datasource;
@synthesize datasourcePoints = _datasourcePoints;
-(void)setupArray
self.perks = [[NSMutableDictionary alloc] init];
[self.perks setObject:@"200" forKey:@"10% Discount"];
[self.perks setObject:@"100" forKey:@"250php Off"];
self.datasource = [self.perks allKeys]; //contains perk's description
self.datasourcePoints = [self.perks allValues]; //contains perk's required points
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
return 2;
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
cell.textLabel.text = [self.datasource objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [self.datasourcePoints objectAtIndex:indexPath.row];
return cell;
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
PerksDetailsViewController *perksDetails = [self.storyboard instantiateViewControllerWithIdentifier:@"detailsOfMyPerks"];
[self.navigationController pushViewController:perksDetails animated:YES];
perksDetails.perkDetailsLabel.text = [self.datasource objectAtIndex:indexPath.row];
perksDetails.pointsLabel.text = [self.perks objectForKey:perksDetails.perkDetailsLabel.text];
- (void)viewDidLoad
//show the number of points of the selected Card
self.pointsLabel.text = self.myPoints;
[self setupArray];
[super viewDidLoad];
PerksDetailsViewController.m
#import "PerksDetailsViewController.h"
#import "Card.h"
#import "CardWalletViewController.h"
#import "BarcodeViewController.h"
@interface PerksDetailsViewController ()
@end
@implementation PerksDetailsViewController
@synthesize pointsLabel = _pointsLabel;
@synthesize perkDetailsLabel = _perkDetailsLabel;
@synthesize perkDetailText = _perkDetailText;
@synthesize pointsText = _pointsText;
@synthesize delegate = _delegate;
@synthesize pointsRequired = _pointsRequired;
- (IBAction)redeemPressed:(id)sender
// get required points of a perk selected
// cast the NSString value to an NSInteger
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
self.pointsRequired = [f numberFromString: (self.pointsLabel.text)];
NSLog(@"points required by the perk %@", self.pointsRequired);
[self.delegate perksDetailsViewController:self didPassRequiredPoints:self.pointsRequired];
if (!self.delegate)
NSLog(@"delegate is nil");
PerksDetailsViewController.h
#import <UIKit/UIKit.h>
#import "BarcodeViewController.h"
@class PerksDetailsViewController;
@protocol PerksDetailsDelegate <NSObject>
- (void)perksDetailsViewController:(PerksDetailsViewController *)sender
didPassRequiredPoints: (NSNumber *) requiredPoints;
@end
@interface PerksDetailsViewController : UIViewController
NSString *perkDetailText;
NSString *pointsText;
IBOutlet UILabel *perkDetailsLabel;
IBOutlet UILabel *pointsLabel;
@property (nonatomic, retain) IBOutlet UILabel *perkDetailsLabel, *pointsLabel;
@property (nonatomic, retain) NSString *perkDetailText, *pointsText;
@property (nonatomic, weak) NSNumber *pointsRequired;
@property (nonatomic, weak) id <PerksDetailsDelegate> delegate;
@end
现在这个 ViewController 实现了两个委托方法
BarCodeViewController.h
#import <UIKit/UIKit.h>
@interface BarcodeViewController : UIViewController
@property (nonatomic, strong) NSNumber *myPoints;
@end
BarCodeViewController.m
#import "BarcodeViewController.h"
#import "CardWalletViewController.h"
#import "Card.h"
#import "PerksDetailsViewController.h"
@interface BarcodeViewController () <CardWalletDelegate, PerksDetailsDelegate>
@end
@implementation BarcodeViewController
@synthesize myPoints = _myPoints;
- (void)perksDetailsViewController:(PerksDetailsViewController *)sender didPassRequiredPoints:(NSNumber *)requiredPoints
self.myPoints = requiredPoints;
- (void)cardWalletViewController:(CardWalletViewController *)sender withCurrentCard:(Card *)currentCard
Card *myCurrentCard = currentCard;
[myCurrentCard.pointsToDeduct addObject:self.myPoints];
NSLog(@"contents :%@", [myCurrentCard.pointsToDeduct description]);
@end
【问题讨论】:
设置 PerksDetailsViewController 的委托属性的代码在哪里? 稍后会发布,敬请期待。 【参考方案1】:首先,你的委托对象属性声明
@property (nonatomic, strong) id <PerksDetailsDelegate> delegate;
应该从 strong
更改为 weak
,因为你的班级不拥有它。
其次,您永远不会为您的班级设置委托对象。这就是为什么它是nil
的原因。我的猜测是BarCodeViewController
(您的PerksDetailsDelegate
协议实现类)应该是CardDetailsViewController
的实例变量,而您错过了将其设置为perksDetails
中perksDetails
对象的代表@。
编辑。
您应该在CardDetailsViewController
类中有一个BarCodeViewController
的实例(命名为bcvController
,对于下面的示例代码):
CardDetailsViewController.m
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
PerksDetailsViewController *perksDetails = [self.storyboard instantiateViewControllerWithIdentifier:@"detailsOfMyPerks"];
[perksDetails setDelegate:bcvController]; // bcvController should be created before this line
[self.navigationController pushViewController:perksDetails animated:YES];
perksDetails.perkDetailsLabel.text = [self.datasource objectAtIndex:indexPath.row];
perksDetails.pointsLabel.text = [self.perks objectForKey:perksDetails.perkDetailsLabel.text];
编辑 2
BarCodeViewController.h
#import <UIKit/UIKit.h>
#import "CardWalletViewController.h"
#import "Card.h"
#import "PerksDetailsViewController.h"
@interface BarcodeViewController : UIViewController <CardWalletDelegate, PerksDetailsDelegate>
@property (nonatomic, strong) NSNumber *myPoints;
@end
BarCodeViewController.m
#import "BarcodeViewController.h"
// @interface BarcodeViewController ()
//
// @end
@implementation BarcodeViewController
@synthesize myPoints = _myPoints;
- (void)perksDetailsViewController:(PerksDetailsViewController *)sender didPassRequiredPoints:(NSNumber *)requiredPoints
self.myPoints = requiredPoints;
- (void)cardWalletViewController:(CardWalletViewController *)sender withCurrentCard:(Card *)currentCard
Card *myCurrentCard = currentCard;
[myCurrentCard.pointsToDeduct addObject:self.myPoints];
NSLog(@"contents :%@", [myCurrentCard.pointsToDeduct description]);
@end
编辑 3
如果你想显示一个 BarcodeViewController,你应该使用这个对象的 bcvController。
CardDetailsViewController.m
#import "CardDetailsViewController.h"
#import "PerksDetailsViewController.h"
#import "Card.h"
@implementation CardDetailsViewController
@synthesize pointsLabel = _pointsLabel;
@synthesize myPoints = _myPoints;
@synthesize perks = _perks;
@synthesize datasource = _datasource;
@synthesize datasourcePoints = _datasourcePoints;
@synthesize bcvController = _bcvController; // new instance variable
// other functions removed for clarity
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
PerksDetailsViewController *perksDetails = [self.storyboard instantiateViewControllerWithIdentifier:@"detailsOfMyPerks"];
[perksDetails setDelegate:bcvController];
[self.navigationController pushViewController:perksDetails animated:YES];
perksDetails.perkDetailsLabel.text = [self.datasource objectAtIndex:indexPath.row];
perksDetails.pointsLabel.text = [self.perks objectForKey:perksDetails.perkDetailsLabel.text];
- (void)viewDidLoad
//show the number of points of the selected Card
self.pointsLabel.text = self.myPoints;
[self setupArray];
[self setBcvController:[self.storyboard instantiateViewControllerWithIdentifier:@"myBarcodeVC"]]; // use setter to retain object properly
[super viewDidLoad];
【讨论】:
谢谢!我已经把它从强变弱了。关于您的第二条建议,我该如何处理?在您最方便的时候给我一些样品。 我由此创建了 bcvController,BarcodeViewController *bcvController = [self.storyboard instantiateViewControllerWithIdentifier:@"myBarcodeVC"];这个好用吗? 我只是把它放在perksDetails的创建下。但是在这样做时,发生了一个错误,说“将'BarCodeViewController *_strong'发送到不兼容类型'id@property (nonatomic, strong) UIViewController *barCodeVC;
我猜现在正在设置委托对象。我已经编辑了使用if (self.delegate) NSLog(@"delegate is not nil");
来检查它的方法。单击redeemPressed 后,现在会出现此NSLog 消息。即使它现在设置了委托对象,我现在在[perksDetails setDelegate: self.barCodeVC];
行上收到一条警告,说“将 'UIViewController*' 发送到不兼容类型 'id以上是关于如何解决仍然为零的委托的主要内容,如果未能解决你的问题,请参考以下文章