I have a button which I'm trying to set the image for when a thread is finished. My code may seem useless to just change the image button but this is for practise and going onto a bigger thing.
Goal: Set the image for the b0 as button_x.png (found in the project).
Issue: The button image is not changing, if I make a connection between the button found on the storyboard to the viewController button declaration I get a crash with -[UIButton setImage:]: unrecognized selector sent to instance 0x8b4c270.
Thank you.
ViewController.h:
#interface ViewController : UIViewController {
IBOutlet UIButton *b0;
Game *instanceOfGame;
}
#property (nonatomic, strong) UIButton *b0;
#property (nonatomic, strong) Game *instanceOfGame;
#end
ViewController.m:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize instanceOfGame;
#synthesize b0;
static NSString *postName = #"123";
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(post:) name:postName object:nil];
instanceOfGame = [[Game alloc] init];
[instanceOfGame start];
}
- (void) post: (NSNotification *) result {
NSNumber *str = [result object];
if (str == 0) {
[self.b0 performSelectorOnMainThread:#selector(setImage: ) withObject:[UIImage imageNamed:#"button_x.png"] waitUntilDone:NO];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Game.h:
#import <Foundation/Foundation.h>
#interface Game : NSObject
#property (nonatomic, strong) NSNumber *choice;
#property (nonatomic, strong) NSNotificationCenter *ns;
-(void) start;
#end
Game.m:
#import "Game.h"
#implementation Game
NSNotificationCenter *ns;
#synthesize ns;
#synthesize choice;
static NSString *postName = #"123";
-(id) init {
if (self = [super init]) {
ns = [NSNotificationCenter defaultCenter];
}
return self;
}
-(void) start {
[self performSelectorInBackground:#selector(loadData) withObject:Nil];
}
-(void) loadData {
choice = 0;
[ns postNotificationName:postName object:choice];
}
#end
UIButton doesn't have a setImage: function, hence the exception being thrown.
It does have this function though:
- (void)setImage:(UIImage *)image forState:(UIControlState)state
Try replacing:
[self.b0 performSelectorOnMainThread:#selector(setImage: ) withObject:[UIImage imageNamed:#"button_x.png"] waitUntilDone:NO];
With a similar sort of implementation done using GCD calling the correct function:
dispatch_async(dispatch_get_main_queue(), ^{
[self.b0 setImage:[UIImage imageNamed:#"button_x.png"] forState:UIControlStateNormal];
});
#Colin Cornaby saying write.
UIButton doesn't have setImage method.
You can also use the same existing code. just update below line
[self.b0 performSelectorOnMainThread:#selector(setImage: ) withObject:[UIImage imageNamed:#"button_x.png"] waitUntilDone:NO];
as
[self performSelectorOnMainThread:#selector(setImage: ) withObject:[UIImage imageNamed:#"ListDropDown.png"] waitUntilDone:NO];
and then define method setImage:
-(void)setImage:(UIImage *)img
{
[self.bo setImage:img forState:UIControlStateNormal];
}
I hope it will work for you
Try this,
if (str == 0) {
dispatch_sync(dispatch_get_main_queue(), ^{
[self.b0 setImage:[UIImage imageNamed:#"button_x.png"] forState:UIControlStateNormal];
});
}
Related
The title says it, I'd like to ask why the following does not work, as it should imho.
// ViewController.m
#import "B.h"
...
#implementation ViewController
{
B *bInstance;
}
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])
{
bInstance = [[B alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
[bInstance setBlockCalled:^(NSDictionary *dict) {
NSLog(#"%#", dict[#"key"]);
}];
[self.view addSubview:bInstance];
}
return self;
}
// B.h
#import <UIKit/UIKit.h>
#interface B : UIView
#property (nonatomic, copy) void (^blockCalled)(NSDictionary *);
#end
// B.m
#import "B.h"
#import "A.h"
#implementation B
{
A *aInstance;
void (^blockCalled)(NSDictionary *);
}
#synthesize blockCalled;
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
aInstance = [[A alloc] initWithFrame:frame];
[aInstance setBlockCalled:blockCalled];
[self addSubview:aInstance];
}
return self;
}
#end
// A.h
#import <UIKit/UIKit.h>
#interface A : UIView
#property (nonatomic, copy) void (^blockCalled)(NSDictionary *);
#end
// A.m
#import "A.h"
#implementation A
{
void (^blockCalled)(NSDictionary *);
}
#synthesize blockCalled;
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setFrame:CGRectMake(0, 0, 100, 100)];
[button setBackgroundColor:[UIColor redColor]];
[button addTarget:self action:#selector(buttonClicked) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:button];
}
return self;
}
- (void) buttonClicked
{
blockCalled(#{#"key":#"value"});
}
#end
What I want to do is 'traverse up the view hiearchy', and as far as I see it, I'm assigning a block variable with the same arguments, so I'd expect it to work. Any reason why this is a wrong idea?
EDIT: added more complete example as of when this issue might happen.
EDIT2: added MCVE, which I've tested.
After I've checked the MCVE, the code crashes on the line blockCalled(#{#"key":#"value"}); in A.m because the blockCalled is nil.
Updated question: I'd like to know why calling [aInstance setBlockCalled:blockCalled] doesn't set the blockCalled in A, as it seems to me to be the same as
[aInstance setBlockCalled:^(NSDictionary *dict)
{
__strong typeof (self) strongSelf = self;
strongSelf.blockCalled(dict);
}];
#implementation ViewController
{
B *bInstance;
}
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])
{
bInstance = [[B alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
[bInstance setBlockCalled:^(NSDictionary *dict) {
NSLog(#"%#", dict[#"key"]);
}];
[self.view addSubview:bInstance];
}
At the moment of initializing bInstance, you haven't set the block yet. It means
aInstance = [[A alloc] initWithFrame:frame];
[aInstance setBlockCalled:blockCalled];
is called before
[bInstance setBlockCalled:^(NSDictionary *dict) {
NSLog(#"%#", dict[#"key"]);
}];
You should override the block setter in B and call it on A.
// B.m
-(void)setBlockCalled(void(^)(NSDictionary*))passedBlock{
[a setBlockCalled:passedBlock];
}
The code in your question (a) uses ivars and #synthesize statements that are unnecessary; and (b) this code snippet is insufficient to reproduce the crash you describe.
Having said that, there are two possible source of crashes that are suggested by the code sample in the question, namely: (a) the code fails to remove the observer if A is deallocated; and (b) it really should double-check to make sure that blocks are non-nil before trying to call them.
But, consider the following:
// A.h
#interface A : UIView
#property (nonatomic, copy) void (^blockCalled)(NSDictionary *dict);
#end
// A.m
#implementation A
- (instancetype) initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleNotification:) name:#"kNotification" object:nil];
}
return self;
}
- (void)handleNotification:(NSNotification *)notification {
// never just call `blockCalled`; always check to see if not null
if (self.blockCalled) {
// everything is good, so let's call the block
self.blockCalled(notification.userInfo);
}
}
- (void)dealloc {
// never just `addObserver`; make sure to remove the observer when this is deallocated
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"kNotification" object:nil];
}
#end
// B.h
#interface B : UIView
#property (nonatomic, copy) void (^blockCalled)(NSDictionary *dict);
#property (nonatomic, strong) A *aInstance;
#end
// B.m
#implementation B
- (void) someMethod {
// !!!!! why this crashes the app when blockCalled on aInstance is called:
[self.aInstance setBlockCalled:self.blockCalled];
// but this does not crash when the same happens
__weak typeof (self) weakSelf = self;
self.aInstance.blockCalled = ^(NSDictionary *dict) {
__strong typeof (self) strongSelf = weakSelf;
// again, never just call `blockCalled`; always check to see if not null
if (strongSelf.blockCalled) {
strongSelf.blockCalled(dict);
}
};
}
#end
Bottom line, when I fix the two obvious sources of crashes (failing to remove observer and failing to check to make sure the block was non-nil before calling it), and test it with logical scenario, it seems to work fine:
- (void)viewDidLoad {
[super viewDidLoad];
B *b = [[B alloc] init];
b.blockCalled = ^(NSDictionary *dict) {
NSLog(#"%#", dict);
};
A *a = [[A alloc] init];
b.aInstance = a;
[b someMethod];
[self.view addSubview:a];
[self.view addSubview:b];
NSDictionary *dict = #{#"foo": #"bar", #"baz": #"qux"};
[[NSNotificationCenter defaultCenter] postNotificationName:#"kNotification" object:nil userInfo:dict];
}
So, assuming one of these two issues wasn't the source of the problem, you must provide MCVE that we can use to reproduce the crash you describe.
Sorry about the confusion.
What I want to do:
enter a string in a textfield in a view(EnterCommandViewController) and click save button, which will dismiss current view and go back to another view(DetectionViewController) and show the string in the UILabel in current view(DetectionViewController). So I have put define the delegate protocol in EnterCommandViewController, my question is that why the respondToSelector, which is used to check whether someone is listening does not work.
I am really a beginner in iOS, I am right now writing a delegate to send text got form UITextField to a UILabel, But I found that the respondToSelector cannot be called by using NSLog for testing.
Below is my code for reference:
EnterCommandViewController.h
#import <UIKit/UIKit.h>
#import "RscMgr.h"
#protocol EnterCommandDelegate <NSObject>
-(void) commandEntered:(NSString*)command;
#end
#interface EnterCommandViewController : UIViewController <RscMgrDelegate>
{
RscMgr* rscMgr;
__weak IBOutlet UITextField *inputTextField;
__unsafe_unretained id<EnterCommandDelegate> delegate;
}
-(void)sendMessage:(NSString*)message;
- (IBAction)cancelPressed;
- (IBAction)savePressed;
#property (nonatomic,assign)id delegate;
#end
EnterCommandViewController.m
#import "EnterCommandViewController.h"
#interface EnterCommandViewController () <UITextFieldDelegate>
{
#private
BOOL connected;
}
#end
#implementation EnterCommandViewController
#synthesize delegate;
- (void)viewDidLoad {
[super viewDidLoad];
rscMgr = [[RscMgr alloc] init];
[rscMgr setDelegate:self];
// Do any additional setup after loading the view, typically from a nib.
inputTextField.text=#"";
[inputTextField becomeFirstResponder];
}
-(void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
inputTextField.delegate = self;
}
-(void) viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
inputTextField.delegate = nil;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)cancelPressed {
[self dismissViewControllerAnimated:YES completion:^{}];
}
- (IBAction)savePressed {
//is anyone listening
NSLog(#"the command is %#",inputTextField.text);
NSLog(#"Checking -- SomeMethod is listening");
if([delegate respondsToSelector:#selector(commandEntered:)]){
NSLog(#"SomeMethod is listening");
//send delegate function with the command entered by the user
[delegate commandEntered:inputTextField.text];
}
[self dismissViewControllerAnimated:YES completion:^{}];
}
DetectionViewController.h
#import <UIKit/UIKit.h>
#import "EnterCommandViewController.h"
#interface DetectionViewController : UIViewController <EnterCommandDelegate>{
__weak IBOutlet UILabel *showCommand;
}
- (IBAction)showSettings:(UIBarButtonItem *)sender;
#end
DetectionViewController.m
#import <Foundation/Foundation.h>
#import "DetectionViewController.h"
#implementation DetectionViewController
- (IBAction)showSettings:(UIBarButtonItem *)sender {
}
-(void) viewDidLoad{
[super viewDidLoad];
showCommand.text=#"";
EnterCommandViewController* enterCVC = [[EnterCommandViewController alloc] init];
enterCVC.delegate = self;
}
#pragma mark - EnterCommandDelegate function(s)
-(void) commandEntered:(NSString *)command{
// showCommand.text = command;
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"command: %#",command);
[self->showCommand setText:command];
});
}
#end
AppDelegate.m
#import "AppDelegate.h"
#interface AppDelegate ()
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
return YES;
}
You are not setting the delegate properly.
EnterCommandViewController* enterCVC = [[EnterCommandViewController alloc] init];
enterCVC.delegate = self;
This is not the way of setting the delegate in your case, since you are not using the created instance of enterCVC, instead a new instance is created from the storyboard when you are transitioning toEnterCommandViewController `(From your comment its clear that you are using the storyboard for this).
So what you can do is you should the delegate from prepareForSegue in DetectionViewController like
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get reference to the destination view controller
EnterCommandViewController* enterCVC = [segue destinationViewController];
enterCVC.delegate = self;
}
So perhaps this is a beginner's mistake and super easy to you guys, but i really do not know how to solve it,really appreciate for any suggestions:
Right Now:
1: I have to ViewController: EnterCommandViewController and DetectionViewController
2: I wrote Delegate protocol in EnterCommandViewController and set DetectionViewController as its delegate.
3: About delegate: I have a inputTextField in the EnterCommandView and a "Save" bar button item on the top toolbar in this view. Once I click the save , current view will be dismissed and return back to DetectionView and show the NSString just entered in the UILabel in DetectionView.
Finally, My question is that Why After I alloc and init a EnterCommandViewController instance , that is enterCVS, the instance is still nil as show in end of my post.
Code:
EnterCommandViewController.h
#import <UIKit/UIKit.h>
#import "RscMgr.h"
#protocol EnterCommandDelegate <NSObject>
#optional
-(void) commandEntered:(NSString*)command;
#end
#interface EnterCommandViewController : UIViewController <RscMgrDelegate,EnterCommandDelegate>
{
RscMgr* rscMgr;
IBOutlet UITextField *inputTextField;
// DetectionViewController* detectionViewController;
// __unsafe_unretained id<EnterCommandDelegate> delegate;
}
-(void)sendMessage:(NSString*)message;
-(id)initWithDelegate:(id)delegateToBe;
- (IBAction)cancelPressed;
- (IBAction)savePressed;
#property (nonatomic,weak) id<EnterCommandDelegate> delegate; //assign replaced
#end
EnterCommandVIewController.m
#import "EnterCommandViewController.h"
#import "DetectionViewController.h"
#interface EnterCommandViewController () <UITextFieldDelegate>
{
#private
BOOL connected;
}
#end
#implementation EnterCommandViewController
#synthesize delegate;
- (void)viewDidLoad {
[super viewDidLoad];
rscMgr = [[RscMgr alloc] init];
[rscMgr setDelegate:self];
// Do any additional setup after loading the view, typically from a nib.
[inputTextField becomeFirstResponder];
}
-(id)initWithDelegate:(id)delegateToBe{
if(self = [super init]){
delegate = delegateToBe;
}
return self;
}
-(void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
inputTextField.delegate = self;
}
-(void) viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
inputTextField.delegate = nil;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - UITextFieldDelegate Methods
-(BOOL) textFieldShouldReturn:(UITextField *)textField{
[self sendMessage:textField.text];
textField.text = nil;
return NO;
}
#pragma mark - Serial Tx/Rx Methods Implementation
-(void) sendMessage:(NSString *)message{
if(connected == YES) {
[rscMgr writeString:message];
}
else{
NSLog(#"CableDisconnected!");
NSLog(#"Attempted To Send: %#",message);
}
}
- (IBAction)cancelPressed {
[self dismissViewControllerAnimated:YES completion:^{}];
}
- (IBAction)savePressed {
//is anyone listening
if([[[UIDevice currentDevice]systemVersion] compare:#"7.0" options:NSNumericSearch] != NSOrderedAscending){
NSLog(#"SYStem version > 7.0");
}
if(delegate&&[delegate respondsToSelector:#selector(commandEntered:)]){
NSLog(#"SomeMethod is listening");
[delegate commandEntered:inputTextField.text];
}
[self dismissViewControllerAnimated:YES completion:nil]; //commened: ^{}
}
#pragma mark - RscMgrDelegate Methods Implementation
-(void) cableConnected:(NSString *)protocol{
inputTextField.text = #"cableConnected";
[rscMgr setBaud:9600];
[rscMgr open];
connected = YES;
}
-(void) cableDisconnected{
inputTextField.text = #"cableDisconnected";
connected = NO;
}
-(void) readBytesAvailable:(UInt32)length{}
-(void) portStatusChanged{}
#end
DetectionViewController.h
#import <UIKit/UIKit.h>
#import "EnterCommandViewController.h"
#interface DetectionViewController : UIViewController <EnterCommandDelegate>{
}
- (IBAction)showSettings:(UIBarButtonItem *)sender;
#property (nonatomic, strong) EnterCommandViewController* enterCVC;
#property (nonatomic, strong) IBOutlet UILabel *showReceivedCommand;
#end
DetectionViewController.m
#import <Foundation/Foundation.h>
#import "DetectionViewController.h"
#import "EnterCommandViewController.h"
#implementation DetectionViewController
#synthesize showReceivedCommand;
#synthesize enterCVC;
- (IBAction)showSettings:(UIBarButtonItem *)sender {
}
-(void) viewDidLoad{
[super viewDidLoad];
if(showReceivedCommand){
showReceivedCommand.text=#"Initial text";
NSLog(#"UILAbel in ViewDidload is not nil");
}else {
NSLog(#"UILAbel in viewDidload is nil");
}
enterCVC = [[EnterCommandViewController alloc] init];
if(enterCVC.delegate) NSLog(#"X nil");
[enterCVC setDelegate:self];
}
#pragma mark - EnterCommandDelegate function(s)
-(void)commandEntered:(NSString *)command{
dispatch_async(dispatch_get_main_queue(), ^{
if(showReceivedCommand){
NSLog(#"UILabel is not nil");
}else{NSLog(#"UILabel is nil");}
showReceivedCommand = [[UILabel alloc] init];
NSLog(#"command received: %#",command);
showReceivedCommand.text = command;
[showReceivedCommand setNeedsDisplay];
NSLog(#"text in showReceivedCommand is %#",showReceivedCommand.text);
});
}
#end
I set a break point at DetectionViewController.n --> ViewDidLoad() --> [enterCVC setDelegate:self];
I got:
self DetectionViewController * 0x15c50e850 0x000000015c50e850
UIViewController UIViewController
showReceivedCommand UILabel * 0x15c510650 0x000000015c510650
enterCVC EnterCommandViewController * 0x15c611360 0x000000015c611360
showReceivedCommand UILabel * 0x15c510650 0x000000015c510650
enterCVC EnterCommandViewController * 0x15c611360 0x000000015c611360
UIViewController UIViewController
rscMgr RscMgr * nil 0x0000000000000000
inputTextField UITextField * nil 0x0000000000000000
connected BOOL NO false
delegate id 0x0 0x0000000000000000
enterCVC = [[EnterCommandViewController alloc] init]
Try changing that to....
enterCVC = [[EnterCommandViewController alloc] initWithDelegate:self];
I haven't found a similar question that could answer my question.
My Question is: Why can't I access a UILabel from another class after the dissmissViewController?
Here is my Code:
ClassA.h:
#interface ClassA : UIViewController {
UILabel *_ErrorLabel;
UIActivityIndicatorView *_acIn1;
}
#property (weak, nonatomic) IBOutlet UILabel *ErrorLabel;
#property (weak, nonatomic) IBOutlet UIActivityIndicatorView *acIn1;
ClassA.m:
shouldPerformSegue, prepareForSegue and statusBarStyle Methods
ClassB.h:
- (IBAction)dismiss;
ClassB.m:
- (IBAction)dismiss
{
[self dismissViewControllerAnimated:YES completion:^{
ClassA *login = [[ClassA alloc] init];
[[login ErrorLabel] setText:#"Please use login."];
[[login acIn1] stopAnimating];
[[login acIn1] setHidesWhenStopped:YES];
[[login acIn1] setHidden:YES];
}];
}
Here is my Code I really hope somebody can help me: I AM ABOUT TO GIVE UP I DON'T KNOW WHY THIS WON'T WORK!
Thanks for your help.
~Markus
Edit1:
I have a ViewController ClassA that contains two text fields and when you click on login you come to a TabBarController where one tab contains the ClassB ViewController and in the ClassB ViewController there is a logout button --> dismiss and when you click this button you should come to the ClassA ViewController AND the ErrorLabel Text should change.
Complete Class: A --> LoginViewControler.h
#import <UIKit/UIKit.h>
#import "ShowProfileViewController.h"
#interface LoginViewController : UIViewController <ShowProfileViewControllerDelegate> {
UILabel *_ErrorLabel;
UIActivityIndicatorView *_acIn1;
}
#property (weak, nonatomic) IBOutlet UITextField *usernameTextField;
#property (weak, nonatomic) IBOutlet UITextField *passwordTextField;
#property (weak, nonatomic) IBOutlet UILabel *ErrorLabel;
#property (weak, nonatomic) IBOutlet UIActivityIndicatorView *acIn1;
#end
Complete Class: A --> LoginViewController.m
#import "LoginViewController.h"
#import "NewsNavigationController.h"
#import "TabViewController.h"
#interface LoginViewController () <UITextFieldDelegate>
#end
#implementation LoginViewController
#synthesize usernameTextField;
#synthesize passwordTextField;
#synthesize ErrorLabel;
#synthesize acIn1;
- (void)viewDidLoad
{
[super viewDidLoad];
[usernameTextField setDelegate:self];
[passwordTextField setDelegate:self];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
{
if([identifier isEqualToString:#"login"])
{
[acIn1 startAnimating];
[acIn1 setHidden:NO];
if([self login]){
return YES;
} else {
[self showErrorMessage:#"Data not correct!"];
[acIn1 stopAnimating];
[acIn1 setHidesWhenStopped:YES];
[acIn1 setHidden:YES];
return NO;
}
}
else {
[acIn1 stopAnimating];
[acIn1 setHidesWhenStopped:YES];
[acIn1 setHidden:YES];
return NO;
}
}
- (void)showErrorMessage:(NSString *)message
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error!"
message:message
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
- (BOOL)login
{
NSString *usernameS = usernameTextField.text;
NSString *passwordS = passwordTextField.text;
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://localhost:8888/login.php?username=%#&password=%#", usernameS, passwordS]]];
NSDictionary *jsonDictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSDictionary *loginDic = [jsonDictionary objectForKey:#"login"];
NSString *ErrorString = [loginDic objectForKey:#"returnString"];
NSLog(#"[+] Login: %#", ErrorString);
if ([ErrorString isEqualToString:#"Success"]){
ErrorLabel.text = #"Login";
return YES;
}
else {
ErrorLabel.text = ErrorString;
return NO;
}
}
- (void)didDismissViewController
{
[ErrorLabel setText:#"Bitte benutzen Sie den Login."];
[acIn1 stopAnimating];
[acIn1 setHidesWhenStopped:YES];
[acIn1 setHidden:YES];
}
- (void)prepareForSegue:(UIStoryboardSegue *)inSegue sender:(id)inSender
{
if([inSegue.identifier isEqualToString:#"login"])
{
ShowProfileViewController *vc = [[ShowProfileViewController alloc] init];
vc.delegate = self;
TabViewController *tabViewController = inSegue.destinationViewController;
NewsNavigationController *theController = [[tabViewController viewControllers] objectAtIndex:0];
[self presentViewController:vc animated:YES completion:nil];
}
}
#end
Complete Class: B --> ShowProfileViewController.h
#import <UIKit/UIKit.h>
#protocol ShowProfileViewControllerDelegate
- (void)didDismissViewController;
#end
#interface ShowProfileViewController : UIViewController
#property (nonatomic, assign) id<ShowProfileViewControllerDelegate> delegate;
- (IBAction)dismiss;
#end
Complete Class: B --> ShowProfileViewController.m
#import "ShowProfileViewController.h"
#import "LoginViewController.h"
#interface ShowProfileViewController ()
#end
#implementation ShowProfileViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
-(BOOL) textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
- (void)viewWillAppear:(BOOL)inAnimated
{
[super viewWillAppear:inAnimated];
}
- (IBAction)dismiss
{
[self dismissViewControllerAnimated:YES completion:^{
[self.delegate didDismissViewController];
}];
}
#end
This doesn't work because inside your completion block, you're creating a new instance of your LoginViewController, and setting its text. What you should be actually doing is setting the text of the existing LoginViewController, that should appear after dismissing ShowProfileViewController
In order to achieve your desired behaviour, you can use the delegation pattern. If you're not familiar with this technique, it'd be very important to learn. It's is used all over the place in iOS and Mac OS X development.
The code below might require some tweaking on your side.
In ShowProfileViewController.h, add before #interface:
#protocol ShowProfileViewControllerDelegate
- (void)didDismissViewController
#end
Also, add the following property declaration to ShowProfileViewController:
#property (nonatomic, assign) id<ShowProfileViewControllerDelegate> delegate;
Then, change LoginViewController.h so it looks like
#import "ShowProfileViewController.h"
#interface LoginViewController : UIViewController <ShowProfileViewControllerDelegate> {
UILabel *_ErrorLabel;
UIActivityIndicatorView *_acIn1;
}
#property (weak, nonatomic) IBOutlet UILabel *ErrorLabel;
#property (weak, nonatomic) IBOutlet UIActivityIndicatorView *acIn1;
Now, in ShowProfileViewController.m, replace the code in the dismiss method so it looks like the following:
- (IBAction)dismiss
{
[self dismissViewControllerAnimated:YES completion:^{
[self.delegate didDismissViewController];
}];
}
In LoginViewController.m, add the following method:
- (void)didDismissViewController
{
[[self ErrorLabel] setText:#"Please use login."];
[[self acIn1] stopAnimating];
[[self acIn1] setHidesWhenStopped:YES];
[[self acIn1] setHidden:YES];
}
And finally, you need to set the delegate property in you ShowProfileViewController to point to the LoginViewController instance. Find in LoginViewController.m in which part of your code you create and present the ShowProfileViewController View Controller and set the delegate property to self. If you're using storyboards, you should do it inside prepareForSegue:.
ClassA *login = [[ClassA alloc] init];
is creating a completly new instance.Not the one you used for coming to class B
i have a tab bar and navigation controller for my app. whenever i tap the scan tab, it kept throwing me Thread 1: EXC_BAD_ACCESS error on line:
ZXCapture.m
[output ZXQT(setDelegate:)ZXAV(setSampleBufferDelegate:)self
Here is my code:
tab bar:
TestScanViewController *scannerViewController=[[TestScanViewController alloc] initWithNibName:#"TestScanViewController" bundle:nil];
navigationController =[[UINavigationController alloc] initWithRootViewController:scannerViewController];
in the TestScanViewController.h:
#interface TestScanViewController : UIViewController <ZXCaptureDelegate>
#end
in the TestScanViewController.m:
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>
#import "TestScanViewController.h"
#interface TestScanViewController ()
#property (nonatomic, strong) ZXCapture* capture;
#property (nonatomic, weak) IBOutlet UILabel* decodedLabel;
#end
#implementation TestScanViewController
#pragma mark - View Controller Methods
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(#"%s",__PRETTY_FUNCTION__);
if (self.capture == nil) {
self.capture = [[ZXCapture alloc] init];
self.capture.delegate = self;
self.capture.rotation = 90.0f;
// Use the back camera
self.capture.camera = self.capture.back;
self.capture.layer.frame = self.view.bounds;;
[self.view.layer addSublayer:self.capture.layer];
[self.view bringSubviewToFront:self.decodedLabel];
}else{
[self.capture start];
[self.view.layer addSublayer:self.capture.layer];
}
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
NSLog(#"%s",__PRETTY_FUNCTION__);
[self.capture.layer removeFromSuperlayer];
[self.capture stop];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return toInterfaceOrientation == UIInterfaceOrientationPortrait;
}
#pragma mark - Private Methods
- (NSString*)displayForResult:(ZXResult*)result {
}
return [NSString stringWithFormat:#"Scanned!\n\nFormat: %#\n\nContents:\n%#", formatString, result.text];
}
#pragma mark - ZXCaptureDelegate Methods
- (void)captureResult:(ZXCapture*)capture result:(ZXResult*)result {
if (result) {
// We got a result. Display information about the result onscreen.
[self.decodedLabel performSelectorOnMainThread:#selector(setText:) withObject:[self displayForResult:result] waitUntilDone:YES];
// Vibrate
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
}
}
- (void)captureSize:(ZXCapture*)capture width:(NSNumber*)width height:(NSNumber*)height {
}
#end
just like the examples codes from github:
https://github.com/TheLevelUp/ZXingObjC/blob/master/examples/BarcodeScanner/ViewController.m
I had the same problem. If you are targeting iOS version 6 or higher and using ARC, then the cause of the problem is an incomplete migration to ARC in ZXCapture.m.
Look around line 56 for this code:
#interface ZXCapture ()
#property (nonatomic, assign) dispatch_queue_t captureQueue;
#end
The assign is a leftover from before ARC days. It also causes a compiler warning, which was my clue to the solution.
To solve the problem, change the code into:
#interface ZXCapture ()
#property (nonatomic, strong) dispatch_queue_t captureQueue;
#end