I'm new to iOS Dev, I'm following the Stanford CS193P classes for Fall 2010. I'm on assignment 3 and I'm setting my delegate to my view and by using the debugger I'm noticing the call to my delegate method won't happen, I don't understand what could be happening. My code is as follows:
GraphViewController.h:
#interface GraphViewController : UIViewController <GraphViewDelegate> {
GraphView *graphView;
float scale;
}
#property (retain) IBOutlet GraphView *graphView;
#property float scale;
- (IBAction)zoomIn;
- (IBAction)zoomOut;
#end
GraphViewController.m:
#implementation GraphViewController
#synthesize graphView, scale;
- (NSString *)functionForGraph:(GraphView *)requestor {
NSLog(#"%#", #"culo peluo");
return #"lol";
}
- (float)scaleForGraph:(GraphView *)requestor {
return self.scale;
}
- (IBAction)zoomIn {
}
- (IBAction)zoomOut {
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)dealloc
{
[super dealloc];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
self.graphView.delegate = self;
self.scale = 20;
[self.graphView setNeedsDisplay];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
GraphView.h:
#class GraphView;
#protocol GraphViewDelegate
- (NSString *)functionForGraph:(GraphView *)requestor;
- (float)scaleForGraph:(GraphView *)requestor;
#end
#interface GraphView : UIView {
id <GraphViewDelegate> delegate;
}
#property (assign) id <GraphViewDelegate> delegate;
#end
GraphView.m:
#implementation GraphView
#synthesize delegate;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (void)drawRect:(CGRect)rect
{
CGFloat cgScale = [self.delegate scaleForGraph:self];
[AxesDrawer drawAxesInRect:self.bounds originAtPoint:self.center scale:cgScale];
}
- (void)dealloc
{
[super dealloc];
}
#end
Put a break point on the line where you set the graph view's delegate.
Inspect the graphView variable. Is it nil?
This happens to me all the time and it's always (well nearly always) because I have failed to connect the outlet to the view in interface builder.
Let's say class YourClass is a delegate for some other class. And delegate methods are not called, despite that delegate property is set up.
Most probably the problem is that your class instance, that is a delegate for your other class is released before the delegate method is called on it. Make it more persistent by making this class a property or instance variable of other class or by using dispatch_once. For example,
Change
YourClass *instance = [[YourClass alloc] init];
by
#property(nonatomic, strong) YourClass *instance;
self.instance = [[YourClass alloc] init];
This problem occurs because in ARC everything that is created inside a method (and is not an instance variable) is released, when method finishes. And delegate methods cannot be called, that are invoked by some background process.
I've written a big blog post on this problem. This is pretty common situation.
http://alwawee.com/wordpress/2013/07/31/on-xmppframework-delegate-method-not-being-called/
Ive got a few pointers for ya on this one:
You don't need an iVar (internal Variable) if you have the variable as a property, it will still work, I've never know it not to.
GraphView
#interface GraphView : UIView {
}
#property (assign) id <GraphViewDelegate> delegate;
#end
GraphViewController
#interface GraphViewController : UIViewController <GraphViewDelegate> {
}
#property (retain) IBOutlet GraphView *graphView;
#property float scale;
- (IBAction)zoomIn;
- (IBAction)zoomOut;
#end
You need to set your delegate in your view to be able to use it.
GraphViewController
#implementation GraphViewController
( ... )
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.delegate = self;
}
return self;
}
( ... )
#end
You are not calling the delegate functions anywhere in your GraphView.m. Try testing it out by placing this piece of code in your - (id)initWithFrame:(CGRect)frame method, right before you return.
[self.delegate functionForGraph:nil];
and see if it logs any message to the console.
Of course this is just to test the delegate implementation, you should actually be using this delegate call in some other method in your GraphView.m which is able to process your requestor
Related
I found out, that every time I change the view the new instance of them will be created. (Memory increase every change of the view).
I would like to dealloc the actually view, if I go the the previous one.
This can not be done by dealloc, because I am using ARC.
The "BACK"-Button is just linked to the Config Menu. At the time I need to dealloc the error view to create the new instance next time.
The init of the Error view looks like:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
The other buttons of the config menu are also just linked to the next view. So I do not create the instance of them manually. If you need some other parts of code, I will put it in.
MORE CODE:
Config View:(almost empty, only 3 linked buttons)
#import "ConfigMenuViewController.h"
#interface ConfigMenu ()
#end
#implementation ConfigMenu
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
ErrorView.m:
#import "Error.h"
#import "CANlinkWLAN.h"
#import "SocketConnectionControllerThread.h"
#interface Error ()
#end
#implementation Error
#synthesize canBufferOverflow;
#synthesize canTransmitTimeout;
#synthesize canErrorcounterOverflow;
#synthesize canBusOffError;
#synthesize usbtors232SyntexError;
#synthesize usbtors232FormatError;
#synthesize usbtors232BufferOverflow;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter ]addObserver:self selector:#selector(receivedMessage:) name:#"GET_ERROR_STATUS" object:nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)readError:(id)sender {
[[SocketConnectionControllerThread sharedInstance] sendCommand: GET_ERROR_STATUS];
}
- (void) receivedMessage: (NSNotification *) note{
NSDictionary *userInfo = [note userInfo];
unsigned char error = [(NSNumber *)[userInfo objectForKey:#"GET_ERROR_STATUS"] integerValue];
NSLog(#"Error: %d", (int)error);
[self receivedError: &error];
}
- (void) receivedError:(unsigned char *) msg{
//change some colors ( not important) ;
}
- (void)dealloc{
[[NSNotificationCenter defaultCenter]removeObserver:self name:#"GET_ERROR_STATUS" object:nil];
}
#end
ErrorView.h
#import "ViewController.h"
#interface System : ViewController
{
UILabel *serverEcho;
UILabel *messageEcho;
UILabel *usbtors232Output;
}
- (IBAction)reset:(id)sender;
- (IBAction)setAutobaud:(id)sender;
- (IBAction)readFeedback:(id)sender;
- (void) receivedMessage: (NSNotification *) note;
#property (nonatomic, retain) IBOutlet UILabel *usbtors232Output;
#property (nonatomic, retain) IBOutlet UILabel *messageEcho;
#property (nonatomic, retain) IBOutlet UILabel *serverEcho;
#end
What happens with ARC is that there's a counter automatically incremented of all of the strong pointers to your object. If you set to nil all the strong pointers to it, ARC will automatically dealloc the memory allocated for the object. What you can do is implement the dealloc method in you ErrorView and log something. Then see if it's deallocated. Simply set to nil all pointers pointing to this object and the memory will be freed.
Edit more code :
I think your dealloc method is never called since you add yourself as an observer of UINotification and you remove yourself from it in the dealloc method (which is never called) so it creates a "memory loop" that you never get out of. Try calling
[[NSNotificationCenter defaultCenter]removeObserver:self name:#"GET_ERROR_STATUS" object:nil];
when you press the back button for example.
I found the way. It was much easier as I expected.
- (IBAction)goBack:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
That way I really go back to the previous view and release the allocated memory. +
Quick question,
i have made a custom delegate
PupilView.h
#protocol DismissPupilViewPopoverDelegate
- (int) getPupilViewReason;
#end
#interface PupilView : UIViewController{
id<DismissPupilViewPopoverDelegate> delegate;
}
#property (nonatomic, assign) id<DismissPupilViewPopoverDelegate> delegate;
It is called in PupilView.m like follows
[[self delegate] getPupilViewReason];
in in my maincontroller.h
#import "PupilView.h"
#interface MainScreen : UIViewController<DismissPupilViewPopoverDelegate>
maincontroller.m
-(int) getPupilViewReason
{
return 100;
}
If i put the [[self delegate] getPupilViewReason]; in any function in pupilview.m it works perfectly, returns 100 i can see it with a breakpoint etc.
If i put it in viewdidload it dosn't load, returns 0, dosnt hit breakpoints etc. Any help as to why.
thanks
make a custom init method for the view controller where you pass the delegate so you can set the delegate in the init method before viewdidload is called.
#interface
- initWithDelegate:(id)aDelegate nibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
//...
#end
#implementation
- initWithDelegate:aDelegate nibName:nibNameOrNil bundle:nibBundleOrNil{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
_delegate = aDelegate;
///rest of init implementation
}
}
- (void)viewDidLoad{
[super viewDidLoad];
[self.delegate getPupilViewReason];
}
//...
#end
Go ahead and call. If the delegate is set up properly then it should work. Do you mean when you're doing a segue UI transfer?
Yes, you can call the delegate in viewDidLoad function.
Suppose your delegate(request owner) name is "delegate" then you can call like -
- (void)viewDidLoad
{
[super viewDidLoad];
[<OBJ>.delegate GetPupilViewReason];
}
OBJ - is the instance of a class, have assign the delegate.
How to realize the label text dynamic change? For example,
labe.text = #"1";
the second is the :
label.text = #"2";
You can do this by extending UILabel class.
MyLable.h
#import <UIKit/UIKit.h>
#protocol MyLabelDelegate;
#interface MYLabel : UILabel
#property(nonatomic, unsafe_unretained) id<MyLabelDelegate> delegate;
#end
#protocol MyLabelDelegate <NSObject>
-(void) label:(UILabel *) label didChangeText:(NSString *) string;
#end
My label.m
#implementation MYLabel
#synthesize delegate = _delegate;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
- (void)setText:(NSString *)text{
[super setText:text];
if([self.delegate respondsToSelector:#selector(label:didChangeText:)]){
[_delegate label:self didChangeText:text];
}
}
#end
and you can implement MyLabel delegate in your view controller if want to detect change there
I am Following a tutorial at http://www.raywenderlich.com/14172/how-to-parse-html-on-ios .
Here is my detailviewcontroller.h file.
#import <UIKit/UIKit.h>
#end <-- //errors shows up here.
#interface DetailViewController : UIViewController
#property (strong, nonatomic) id detailItem;
#property (weak, nonatomic) IBOutlet UILabel *detailDescriptionLabel;
#end
This is my detailview.m file
#import "DetailViewController.h"
#interface DetailViewController ()
- (void)configureView;
#end
#implementation DetailViewController
#pragma mark - Managing the detail item
- (void)setDetailItem:(id)newDetailItem
{
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
}
- (void)configureView
{
// Update the user interface for the detail item.
if (self.detailItem) {
self.detailDescriptionLabel.text = [self.detailItem description];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self configureView];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = NSLocalizedString(#"Detail", #"Detail");
}
return self;
}
#end
As i referred above, the #end error message appears and wait to auto fix in red square, the i agree to do the auto fix. Then the xCode applies the #end code over there, as shown in the .h file. Then an other error appears as which is in the title " #end must appear in an objective-c context "
what should i do ?
Is xCode gone mad or what.
Whats wrong ?
In my case, somewhere along the line I missed a #end in one of the .h file. So all files that import that .h file is prompting this error. The funny thing is, I don't receive this error message on the one .h file that does miss the #end. So I guess you need to do some searching make sure you close all your #interface, #implementation or #protocol with #end. Hope that helps.
Just remove that first #end. It's completely wrong. You can only have #end after an #implementation, #interface, or #protocol declaration.
I'm developing an iPhone 3.1.3 application and
I have the following header file:
#import <UIKit/UIKit.h>
#interface VoiceTest01ViewController : UIViewController {
IBOutlet UITextView *volumeTextView;
BOOL isListening;
NSTimer *soundTimer;
}
#property (nonatomic, retain) IBOutlet UITextView *volumeTextView;
#property (nonatomic, retain) NSTimer *soundTimer;
- (IBAction)btnStartClicked:(id)sender;
#end
And .m file is:
#import "VoiceTest01ViewController.h"
#implementation VoiceTest01ViewController
#synthesize volumeTextView;
#synthesize soundTimer;
...
How can I set isListening up to false at start?
All instance variables are set to 0/NULL/nil by default, which in the case of a BOOL means NO. So it already is NO (or false) by default.
If you need any other value then you need to override the designated initializer(s), most of the time init, and set the default value there.
Set the boolean value in your viewDidLoad
- (void)viewDidLoad {
isListening = NO;
//Something
}
The default value for a BOOL field is False, but it's a good place set it in the "viewDidLoad" just as #BuildSucceeded sugest
Greetings
1) init is a good place, like below, but if you are using story board this init method won't be called.
- (id) init {
self = [super init];
if (self) {
isListening = NO;
}
return self;
}
2)
initWithCoder is a good place for your code if you are using storyboard of course your sdk is 3.0, i believe it has not storyboard at that time, but just in case anyone need it:
- (id) initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
isListening = NO;
}
return self;
}
3) If your viewcontroller will be init from nib file:
- (id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
isListening = NO;
}
}