Вопрос

I can't access to my labels, sliders and switches which are all in a UIViewController from my NSData Class.

this is my code so far :

FirstViewController.h

@interface FirstViewController : UIViewController 
@property (strong) IBOutlet UISwitch * mySwitch;
@property (strong) IBOutlet UISlider *myTransitionSlide;
@property (nonatomic,retain) IBOutlet UILabel *labelTest;

myNSDataClass.h

#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>
@class FirstViewController;


@interface myNSDataClass : NSObject <UIApplicationDelegate,CBPeripheralManagerDelegate>
{
    FirstViewController *firstViewController;
}
@property (nonatomic, retain) FirstViewController *firstViewController;

myNSDataClass.m

- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests
{
    self.firstViewController = [[FirstViewController alloc]init];
    [[self.firstViewController labelTest]setText:@"text changed"];                                                  
    [self.firstViewController.myTransitionSlide setValue:1];
    [self.firstViewController.mySwitch setOn:NO animated:YES];
}

I know that the problem come from the reallocation of FirstViewController but I don't know what I should do.

Это было полезно?

Решение

You shouldn't access your outlets from anywhere else but from the view controller that owns them. Also, you'd want do make your outlets weak.

To solve your problem you could use notifications:

- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests
{
   [[NSNotificationCenter defaultCenter] postNotificationName:@"MyAppDidReceiveWriteRequestNotification" 
                                                       object:nil 
                                                     userInfo:@{@"text": @"text changed", @"switchOn": @(NO)}];
}

Then, in your FirstViewController, you register yourself as an observer for that notification, for example in viewDidLoad:

- (void)viewDidLoad
{
    [super viewDidLoad];

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

}

And you implement the handler:

- (void)handleDidReceiveWriteRequestNotification:(NSNotification *)note
{
  [self.labelTest setText:note.userInfo[@"text"]];
  [self.mySwitch setOn:[note.userInfo[@"switchOn"] boolValue] animated:YES];
}

And you clean up:

- (void)dealloc
{
   [[NSNotificationCenter defaultCenter] removeObserver:self];
}

That's it. Much cleaner.

Also, you'd want to turn the name of the notification and the names of the userInfo dictionary keys into constants so that you don't have the same string literal in multiple places in your code.

Другие советы

You can make it works by adding reference to your FirstViewController. In FirstViewController.m add property or private variable for myNSDataClass object, for example:

//FirstViewController.m
@implementation FirstViewController {
    myNSDataClass *_myData;
}

and later in viewDidLoad add reference to FirstViewController:

-(void)viewDidLoad {
    //Your code here...
    _myData = [[myNSDataClass alloc] init];
    _myData.firstViewController = self;
}

The next step is removing memory leak, change your myNSDataClass.h to: @class FirstViewController;

@interface myNSDataClass : NSObject <UIApplicationDelegate,CBPeripheralManagerDelegate>
@property (nonatomic, weak) FirstViewController *firstViewController; //<- use assign if you support OS < 4
//your code ..
@end

You don't need @synthesize in implementation file if you don't support OS less that 4.

When you know that the problem comes from the re-allocation, then don't reallocate it. It is that simple. :-)

Instead of that you need somewhere to set the firstViewController property of your myNSDataClass accordingly. That may happen in that very moment when your firstViewController is actually instanciated. Where that is depends on the architecture of your app.

If you want it 'neat' then don't let the myNDataClass (which might serve as model) access mySwitch etc. directly. Let it call some method of firstViewController. Only your view controller shold "know" its controls and set them accordingly.

Declaring these method(s) in firstViewController.h should do the trick. However, it would be even neater if you declare them in a protocol which firstViewController implements (confirms to). Instead of including firstViewConroller.h in myNSDataClass.h you should include this protocol (a .h file too).

set a breakpoint before [self.firstViewController.mySwitch setOn:NO animated:YES]; and there you should find the problem. If you print out self.firstViewController.mySwitch, the element should be nil.

So try to set primitive or initialized attributes at this point

for example

// FirstViewController.h

@interface FirstViewController : UIViewController
{
    BOOL switchState;
    NSString *lblTitle;
    float sliderValue;
}

-(void)setSwitchState:(BOOL)pSwitchState andLabelText:(NSString *)pLblTitle andSliderValue:(float)pSliderValue;

// FirstViewController.m

-(void)setSwitchState:(BOOL)pSwitchState andLabelText:(NSString *)pLblTitle andSliderValue:(float)pSliderValue
{
    switchState = pSwitchState;
    lblTitle = pLblTitle;
    sliderValue = pSliderValue;
}

-(void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self.labelTest] setText:pLblTitle];                                     
    [self.myTransitionSlide setValue:pSliderValue];
    [self.mySwitch setOn:pSwitchState animated:YES];
}

and in peripheralManager

- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests
{
   // I don't know if this re-initialization is realy required, so I let it here.
   // If not, you should think of init it somewhere else use the solution with the NSNotificationCenter ;)
   self.firstViewController = [[FirstViewController alloc]init];
   self.firstViewController setSwitchState:NO andLabelText:@"text changed" andSliderValue:1];
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top