目标和问题:
每过一秒后,' regularBubbleCount' - RWGameData的变量 - 增加1.我试图通过传递' regularBubbleCount'的新值来显示此值的变化。对于常规的宝贝标签' PrimaryViewController中的UILabel。我试图通过使用以下代码行
来做到这一点_regularBubLabel.text = [NSString stringWithFormat:@"%li", [RWGameData sharedGameData].regularBubbleCount];
显然这不起作用,因为' regularBubLabel'不是RWGameData类的对象,其中' timerCalled'方法驻留。如何更改' regularBubLabel'的值?从RWGameData类里面?
#import <Foundation/Foundation.h>
@interface RWGameData : NSObject <NSCoding>
@property (assign, nonatomic) long regularBubbleCount;
@property (assign, nonatomic) BOOL dataIsInitialized;
+(instancetype)sharedGameData;
-(void)reset;
-(void)save;
-(void)timerSetup;
-(void)timerCalled;
@end
#import "RWGameData.h"
@implementation RWGameData
static NSString* const SSGameDataRegularBubbleCountKey = @"regularBubbleCount";
static NSString* const SSGameDataIsInitializedKey = @"dataIsInitializedKey";
+ (instancetype)sharedGameData {
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [self loadInstance];
});
return sharedInstance;
}
-(void)reset {
self.regularBubbleCount = 0;
self.dataIsInitialized = true;
}
- (void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeDouble:self.regularBubbleCount forKey: SSGameDataRegularBubbleCountKey];
[encoder encodeBool:self.dataIsInitialized forKey: SSGameDataIsInitializedKey];
}
- (instancetype)initWithCoder:(NSCoder *)decoder
{
self = [self init];
if (self) {
_regularBubbleCount = [decoder decodeDoubleForKey: SSGameDataRegularBubbleCountKey];
_dataIsInitialized = [decoder decodeBoolForKey: SSGameDataIsInitializedKey];
}
return self;
}
+(NSString*)filePath
{
static NSString* filePath = nil;
if (!filePath) {
filePath =
[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]
stringByAppendingPathComponent:@"gamedata"];
}
return filePath;
}
+(instancetype)loadInstance
{
NSData* decodedData = [NSData dataWithContentsOfFile: [RWGameData filePath]];
if (decodedData) {
RWGameData* gameData = [NSKeyedUnarchiver unarchiveObjectWithData:decodedData];
return gameData;
}
return [[RWGameData alloc] init];
}
-(void)save
{
NSData* encodedData = [NSKeyedArchiver archivedDataWithRootObject: self];
[encodedData writeToFile:[RWGameData filePath] atomically:YES];
}
- (void)timerSetup { // to be called from delegate didFinishLaunching….
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerCalled) userInfo:nil repeats:YES];
}
-(void)timerCalled
{
[RWGameData sharedGameData].regularBubbleCount++;
/* THE ISSUE IS HERE */
_regularBubLabel.text = [NSString stringWithFormat:@"%li", [RWGameData sharedGameData].regularBubbleCount];
[[RWGameData sharedGameData] save];
} NSLog(@"Regular Bubble Count: %li", [RWGameData sharedGameData].regularBubbleCount);
}
@end
#import <UIKit/UIKit.h>
#import "RWGameData.h"
@interface PrimaryViewController : UIViewController
@property (strong, nonatomic) IBOutlet UILabel *regularBubLabel;
@end
#import "PrimaryViewController.h"
@interface PrimaryViewController ()
@end
@implementation PrimaryViewController
{
NSString *bubbleImage;
UIImage *backgroundImage;
UIImageView *backgroundImageView;
int r;
int i;
}
- (void)viewDidLoad {
[super viewDidLoad];
backgroundImage = [UIImage imageNamed:@"background_new.png"];
backgroundImageView=[[UIImageView alloc]initWithFrame:self.view.frame];
backgroundImageView.image=backgroundImage;
[self.view insertSubview:backgroundImageView atIndex:0];
}
- (void)viewDidAppear:(BOOL)animated {
_regularBubLabel.text = [NSString stringWithFormat:@"%li", [RWGameData sharedGameData].regularBubbleCount];
_premiumBubLabel.text = [NSString stringWithFormat:@"%li", [RWGameData sharedGameData].premiumBubbleCount];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)increment {
if ([RWGameData sharedGameData].megaBubblePopValue == 0) {
[RWGameData sharedGameData].megaBubblePopValue++;
[[RWGameData sharedGameData] save];
}
if ([@"mysterybubble.png" isEqual:bubbleImage]) {
[RWGameData sharedGameData].premiumBubbleCount += 2;
_premiumBubLabel.text = [NSString stringWithFormat:@"%li", [RWGameData sharedGameData].premiumBubbleCount];
} else if ([@"megaBubbleLarge30.png" isEqual:bubbleImage]) {
[RWGameData sharedGameData].regularBubbleCount += [RWGameData sharedGameData].megaBubblePopValue;
_regularBubLabel.text = [NSString stringWithFormat:@"%li", [RWGameData sharedGameData].regularBubbleCount];
} i++;
}
- (IBAction)save {
[[RWGameData sharedGameData] save];
}
- (IBAction)setBubbleStatus {
r = arc4random_uniform(400);
if (r <= 1) {
bubbleImage = @"mysterybubble.png";
[_megaBubbleButton setImage:[UIImage imageNamed:bubbleImage] forState:UIControlStateNormal];
NSLog(@"Roll SUCCESS. [%i] %i", i, r);
} else {
bubbleImage = @"megaBubbleLarge30.png";
[_megaBubbleButton setImage:[UIImage imageNamed:bubbleImage] forState:UIControlStateNormal];
NSLog(@"Roll FAIL. [%i] %i", i, r);
}
}
@end
答案 0 :(得分:2)
在RWGameData类中有一个IBOutlet是没有意义的,因为它是NSObject的子类。该类在故事板中没有实例(也没有视图),因此您无法连接IBOutlet。实现目标的一种方法是使PrimaryViewController成为RWGameData的委托,并在计时器的action方法中调用委托方法,该方法将传递您需要的任何数据,以便PrimaryViewController可以更新自己的标签。
答案 1 :(得分:0)
我将做出以下假设:
假设#1 -RWGameData在加载应用程序时在ApplicationDelegate中实例化,并且可以在应用程序委托中作为self.gameData
假设#2 - 正如您所说,PrimaryViewController是故事板中的主视图控制器。
假设#3 - 您每隔1秒钟使用NSTimer更新此计数。
假设#4 - 您的故事板文件名为Mainstorybaord
在课程定义之前将其添加到RWGameData.h
。
@class RWGameData;
@protocol RWGameStateProtocol <NSObject>
-(void)StateUpdateForGameData:(RWGameData*)data;
@end
在RWGameData.h
内添加您的班级定义中的委托。
@interface RWGameData : NSObject
@property(weak)id<RWGameStateProtocol> delegate;
@end
在您的选择器timerCalled
中添加对您的委托的调用,通知它数据已更改。
-(void)timerCalled
{
[RWGameData sharedGameData].regularBubbleCount++;
/* THE ISSUE IS HERE */
_regularBubLabel.text = [NSString stringWithFormat:@"%li", [RWGameData sharedGameData].regularBubbleCount];
[[RWGameData sharedGameData] save];
} NSLog(@"Regular Bubble Count: %li", [RWGameData sharedGameData].regularBubbleCount);
/* Inform the delegate */
[self.delegate StateUpdateForGameData:self];
}
一旦定义了协议,您的PrimaryViewcontroller
就会遵循此协议,其内容类似于以下内容。
-(void)StateUpateforGameData:(RWGameData*)data
{
self.regularBubLabel.text = [[NSString alloc]initWithFormat:@"%i",data.regularBubbleCount];
}
剩下的就是在RWGameData
实例上设置委托。您可以通过询问storyboard为您提供主视图控制器的实例来执行此操作。如果您正在使用故事板,则默认情况下此方法为空。但是,由于我们要在显示之前修改主视图控制器,因此我们需要进行一些更改并执行Storyboard已经为您完成的一些工作。
在ApplicationDelegate的头文件中,为UIWindow
和RWGameData
创建一个属性。
@interface YourAppDelegate : UIResponder <UIApplicationDelegate>
@property(strong,nonatomic) UIWindow *window;
@property(strong,nonatomic) RWGameData *gameData;
@end
现在我们已经设置了属性,您需要执行一些额外的工作。请注意,通常您在使用情节提要时不必执行此步骤。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
/// Screen Information
CGFloat scale = [[UIScreen mainScreen]scale];
CGRect frame = [[UIScreen mainScreen]bounds];
UIWindow* window = [[UIWindow alloc]initWithFrame:frame];
self.window = window;
self.window.contentScaleFactor = scale;
UIStoryboard *sb = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
PrimaryViewController *vc = (PrimaryViewController*)[sb instantiateInitialViewController];
RWGameData *gameData = [[RWGameData alloc]init];
gameData.delegate = vc;
self.gameData = gameData;
[window setRootViewController:vc];
[window makeKeyAndVisible];
return YES;
}
这种方法并不要求您将标签和游戏数据紧密结合在一起。相反,对游戏数据的任何更新现在都可以通知您的视图,并允许您的视图选择需要更新的标签。