calling delegates in viewdidload - objective-c

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.

Related

clean up the instance of view after change

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. +

#end must appear in an objective-c context

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.

Passing data to textView from another class

I know this is just a fundamental question but still somewhere I am missing something, I am playing with passing data to a textView from another class. For this I have created two classes one with xib file (ViewController) and another without(secondVC).
What I am trying to do is that I have a textview in ViewController class and wanted to pass the data to this textView from secondVC. This is how I am doing.
//ViewController.h
#import <UIKit/UIKit.h>
#import "secondVC.h"
#interface ViewController : UIViewController{
IBOutlet UITextView *textView;
}
#property (nonatomic, retain) UITextView *textView;
- (IBAction)go:(id)sender;
#end
//ViewController.m
- (IBAction)go:(id)sender{
secondVC *sec = [[secondVC alloc] init];
[sec print];
}
//secondVC.h
#import <UIKit/UIKit.h>
#import "ViewController.h"
#interface secondVC : UIViewController
- (void)print;
#end
//secondVC.m
- (void)print{
NSString *printThis = #"This works";
ViewController *vc = [[ViewController alloc] init];
[vc.textView setText:printThis];
//vc.textView.text = printThis //Tried both
}
Any suggestions would be appreciated.
Thanks
you can do like this :
//ViewController.h
#import <UIKit/UIKit.h>
#import "secondVC.h"
#interface ViewController : UIViewController{
IBOutlet UITextView *textView;
}
#property (nonatomic, retain) UITextView *textView;
- (IBAction)go:(id)sender;
#end
//ViewController.m
- (IBAction)go:(id)sender{
secondVC *sec = [[secondVC alloc] init];
sec.viewController = self;
[sec print];
}
//secondVC.h
#import <UIKit/UIKit.h>
#import "ViewController.h"
#interface secondVC : UIViewController {
ViewController *viewController;
}
#property(nonatomic, retain)ViewController *viewController;
- (void)print;
#end
//secondVC.m
#synthesize viewController;
- (void)print{
NSString *printThis = #"This works";
self.viewController.textView.text = printThis ;
}
Try with protocol... if you want to send string from textView(child) to other ViewController(parent)
You need a delegate method that is fired from the SecondVC and handled in the first one (ViewController).
There are a few issues here:
You've got a ViewController creating a new secondVC and sending it a print message. That's okay, but the implementation of -print creates a different instance of ViewController and tries to set the text of it's textView property. That's clearly not what you want -- you should instead be sending the text back to the original instance of ViewController.
That second instance of ViewController very likely has its textView property set to nil since textView is an outlet, but you haven't loaded its view from the .xib.
It's really not nice for one view controller to mess with the views of another view controller. The secondVC should be giving the text to the original ViewController object, not trying to set the text of one of its views.
To facilitate communication from secondVC to ViewController, give secondVC a property to keep track of the original ViewController. The usual thing to do here is to define a delegate protocol for secondVC and implement that protocol in ViewController. When ViewController creates secondVC, it sets the delegate of secondVC to itself. That gives secondVC a pointer to its delegate (it shouldn't care whether its a ViewController or some other kind of object, as long as the delegate implements the right methods).
.h file:
#import <UIKit/UIKit.h>
#protocol StringDelegate <NSObject>
-(void)getArrayOfStrings:(NSMutableArray*)strArray;
#end
#interface WWSettings : UIViewController{
}
#property(nonatomic,assign)id<StringDelegate>delegate;
#end
.m file:
#import "WWSettings.h"
#implementation WWSettings
#synthesize delegate;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
-(void)blablablaFunction{
[delegate getArrayOfStrings:yourArray];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
#end
if you dont understand how it works .. ask ! i'll make my best to help you )
your secondVC
#import <UIKit/UIKit.h>
#import "WWSettings.h"
#interface secondVC : UIViewController<StringDelegate>{
WWSettings *obj;
}
#end
and .m file :
#import "secondVC.h"
#implementation secondVC
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
-(void)getArrayOfStrings:(NSMutableArray *)strArray{
// here you get your array !!! it's a delegate function made by you in child viewController;
}
- (void)viewDidLoad
{
obj = [[WWSettings alloc]init];
[obj setDelegate:self];
[super viewDidLoad];
// Do any additional setup after loading the view.
}
first VC .h file :
#import <UIKit/UIKit.h>
#protocol textViewChildDelegate <NSObject>
-(void)getStrings:(NSString*)string;
#end
#interface textViewChild : UIViewController<UITextViewDelegate>{
UITextView *textView;
}
#property(nonatomic,assign)id<textViewChildDelegate>delegate;
#end
.m file:
#import "textViewChild.h"
#implementation textViewChild
#synthesize delegate;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
-(void)myWorkingMethod{
// get string from textView
[delegate getStrings:textView.text];
}
- (void)viewDidLoad
{
textView = [[UITextView alloc]initWithFrame:CGRectMake(0, 240, 320, 240)];
[super viewDidLoad];
// Do any additional setup after loading the view.
}
Now go to secondVC .h:
#import <UIKit/UIKit.h>
#import "textViewChild.h"
#interface TextViewViewController : UIViewController<textViewChildDelegate>{
UITextView * myfirstTextView;
}
#end
and to .m file:
#import "TextViewViewController.h"
#implementation TextViewViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)getStrings:(NSString *)string{
myfirstTextView.text = string; // finally we get string from child view controller
}
- (void)viewDidUnload
{
myfirstTextView = [[UITextView alloc]init];
[super viewDidUnload];
// Release any retained subviews of the main view.
}

Obj-C: Delegate method not getting called

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

initialize instance variables on Objective-C

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