UILabel在xcode中被引用为整数指针

时间:2014-12-15 15:35:26

标签: ios objective-c iphone xcode

目标和问题:

每过一秒后,' regularBubbleCount' - RWGameData的变量 - 增加1.我试图通过传递' regularBubbleCount'的新值来显示此值的变化。对于常规的宝贝标签' PrimaryViewController中的UILabel。我试图通过使用以下代码行

来做到这一点
_regularBubLabel.text = [NSString stringWithFormat:@"%li", [RWGameData sharedGameData].regularBubbleCount];

显然这不起作用,因为' regularBubLabel'不是RWGameData类的对象,其中' timerCalled'方法驻留。如何更改' regularBubLabel'的值?从RWGameData类里面?

RWGameData.h

#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

RWGameData.m

#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

PrimaryViewController.h

#import <UIKit/UIKit.h>
#import "RWGameData.h"

@interface PrimaryViewController : UIViewController

@property (strong, nonatomic) IBOutlet UILabel *regularBubLabel;

@end

PrimaryViewController.m

#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

2 个答案:

答案 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

在课程定义之前将其添加到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

一旦定义了协议,您的PrimaryViewcontroller就会遵循此协议,其内容类似于以下内容。

-(void)StateUpateforGameData:(RWGameData*)data
{
   self.regularBubLabel.text = [[NSString alloc]initWithFormat:@"%i",data.regularBubbleCount];
}

申请代表

剩下的就是在RWGameData实例上设置委托。您可以通过询问storyboard为您提供主视图控制器的实例来执行此操作。如果您正在使用故事板,则默认情况下此方法为空。但是,由于我们要在显示之前修改主视图控制器,因此我们需要进行一些更改并执行Storyboard已经为您完成的一些工作。

在ApplicationDelegate的头文件中,为UIWindowRWGameData创建一个属性。

@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;
}

这种方法并不要求您将标签和游戏数据紧密结合在一起。相反,对游戏数据的任何更新现在都可以通知您的视图,并允许您的视图选择需要更新的标签。