I'm trying to understand why one object is not deallocating in my code and how to fix this. I have ARC enabled for all classes and one external library IndoorsSDK-iOS (3.3.0).
I the following code the property del2 is not deallocated (The dealloc method of the IndoorsTestDelegate is not called). The del2 property is passed to Indoors instance in registerLocationListener: message and is removed from it during dealloc in view controller. The dealloc method of View Controller is called when the View Controller is Pushed back in Navigation Controller stack. The del1 dealloc method from IndoorsTestDelegate also is called but del2 dealloc method is not called. And my question is why del2 dealloc method is not called and how can I fix this. I don't have sources from external library.
This is the View Controller code:
#import "IndoorsTestVC.h"
#import "IndoorsTestDelegate.h"
#import <Indoors/Indoors.h>
#import <IndoorsSurface/ISIndoorsSurfaceViewController.h>
#interface IndoorsTestVC ()
#property (strong, nonatomic) IndoorsTestDelegate *del1;
#property (strong, nonatomic) IndoorsTestDelegate *del2;
#end
#implementation IndoorsTestVC
- (void)viewDidLoad
{
[super viewDidLoad];
self.del1 = [[IndoorsTestDelegate alloc]
initWithController:self
andName:#"Del1"];
self.del2 = [[IndoorsTestDelegate alloc]
initWithController:self
andName:#"Del2"];
__unused Indoors *indoors = [[Indoors alloc]
initWithLicenseKey:API_KEY
andServiceDelegate:self.del1];
[[Indoors instance] enableEvaluationMode:NO];
[[Indoors instance] setLogLevel:IDSLogLevelWarning];
[[Indoors instance] registerLocationListener:self.del2];
ISIndoorsSurfaceViewController *surfaceVC = [[ISIndoorsSurfaceViewController alloc] init];
surfaceVC.delegate = self.del1;
// add surfaceVC as a child view controller
[self addChildViewController:surfaceVC];
[self addSubview:surfaceVC.view
withEqualSizeLikeParent:self.view];
[surfaceVC didMoveToParentViewController:self];
// load building
[surfaceVC loadBuildingWithBuildingId:1234];
}
- (void)dealloc {
[[Indoors instance] removeLocationListener:self.del2];
NSLog(#"Dealloc test controller %#", _title);
}
This is the IndoorsTestDelegate.h:
#import <Foundation/Foundation.h>
#import <Indoors/Indoors.h>
#import <IndoorsSurface/ISIndoorsSurfaceViewController.h>
#interface IndoorsTestDelegate : NSObject <IndoorsServiceDelegate, ISIndoorsSurfaceViewControllerDelegate, IndoorsLocationListener>
#property (weak, nonatomic) UIViewController *controller;
#property (strong, nonatomic) NSString *name;
- (instancetype)initWithController:(UIViewController *) controller
andName:(NSString *)name;
#end
And IndoorsTestDelegate.m:
#import "IndoorsTestDelegate.h"
#implementation IndoorsTestDelegate
- (instancetype)initWithController:(UIViewController *)controller
andName:(NSString *)name
{
self = [super init];
if (self) {
_controller = controller;
_name = name;
}
return self;
}
- (void)dealloc {
// This method is called for del1 property
// but for del2 not. Why?
NSLog(#"Dealloc %#", _name);
}
// The protocols methods are empty in testing delegate
#pragma mark IndoorsLocationListener
- (void)zonesEntered:(NSArray *)zones {}
- (void)positionUpdated:(IDSCoordinate *)userPosition {}
- (void)contextUpdated:(IDSContext *)context {}
- (void)changedFloor:(int)floorLevel withName:(NSString *)name {}
- (void)weakSignal {}
- (void)orientationUpdated:(float)orientation {}
#pragma mark ISIndoorsSurfaceViewControllerDelegate
- (void)indoorsSurfaceViewController:(ISIndoorsSurfaceViewController *)indoorsSurfaceViewController isLoadingBuildingWithBuildingId:(NSUInteger)buildingId progress:(NSUInteger)progress {}
- (void)indoorsSurfaceViewController:(ISIndoorsSurfaceViewController *)indoorsSurfaceViewController didFinishLoadingBuilding:(IDSBuilding *)building {}
- (void)indoorsSurfaceViewController:(ISIndoorsSurfaceViewController *)indoorsSurfaceViewController didFailLoadingBuildingWithBuildingId:(NSUInteger)buildingId error:(NSError *)error {}
#pragma mark - IndoorsSurfaceServiceDelegate
- (void)onError:(IndoorsError *)indoorsError {}
- (void)bluetoothStateDidChange:(IDSBluetoothState)bluetoothState {}
- (void)locationAuthorizationStatusDidChange:(IDSLocationAuthorizationStatus)status {}
- (void)connected {}
#end
Related
I'm having trouble figuring out why I'm getting a nil delegate for this call. It seems like I'm setting the delegate just fine.
LogoutViewController.h
#protocol SomeNewDelegate <NSObject>
#required
- (void)someMethod;
#end
#interface LogoutViewController : UIViewController
#property (nonatomic, weak) id<SomeNewDelegate> delegate;
LogoutViewController.m
- (IBAction)logoutButtonTapped:(id)sender {
NSLog(#"logout tapped");
[self.delegate someMethod];
[self dismissViewControllerAnimated:YES completion:nil];
}
MainViewController.m
#interface MainViewController () <UIScrollViewDelegate, SomeNewDelegate>
#property (nonatomic, strong) LogoutViewController *logoutVC;
#end
#implementation MainViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.logoutVC.delegate = self;
}
- (void)someMethod {
NSLog(#"someMethod");
}
someMethod never gets called and I don't see why the delegate is nil. Any help?
Use below code in viewDidload
LogoutViewController *logoutVC = [[LogoutViewController alloc]init];
logoutVC.delegate = self;
Remove LogoutViewController from property.
I have used this and its working fine.
Hope its working for you.
Edited code in .h file
#protocol syncDataDelegate <NSObject>
#required
- (void) offlineSyncProcess;
#end
#interface LoginViewController : UIViewController
{
id <syncDataDelegate> syncDelegate;
}
#property (retain) id syncDelegate;
in .m file
#implementation LoginViewController
{
// your code
}
#synthesize syncDelegate;
- (IBAction)logoutButtonTapped:(id)sender {
NSLog(#"logout tapped");
[syncDelegate offlineSyncProcess];
}
You can call delegate method from here in LoginViewController.m file from any method.
in My Delegate implementation
in .m file
#interface MainViewController ()<syncDataDelegate>
#end
#implementation MainViewController
- (void)viewDidLoad
{
[super viewDidLoad];
LoginViewController *LVC = [[LoginViewController alloc]init];
LVC.syncDelegate = self;
}
now use the delegate methode here
- (void) offlineSyncProcess
{
// your code here
}
this code is working in my project, check this in your project.
Make sure your logoutVC is not nil when you try to set the delegate property for it.
You can implement the setDelegate method in your LogoutViewController.m. Then use break point to make sure it is invoked.
Delegate is nil because your logoutVC is nil, you haven't allocated memory to the logoutvc property.
Just before self.logoutVC.delegate = self
Add following code
self.logoutVC = [[LogoutViewController alloc]init];
Everything will start working automatically.
AddBillViewController.h:
#protocol AddBillDelegate <NSObject>
- (void)addBillViewControllerDidAddOneBill;
#end
#interface AddBillViewController : UIViewController
#property (retain, nonatomic)id <AddBillDelegate> delegate;
#end
AddBillViewController.m:
- (IBAction)AddBill:(id)sender {
[self.delegate addBillViewControllerDidAddOneBill];
[self dismissViewControllerAnimated:YES completion:nil];
}
HomeViewController.m:
#interface HomeViewController () <AddBillDelegate>
#property (strong, nonatomic)AddBillViewController *abVC;
#end
#implementation HomeViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.abVC = [[AddBillViewController alloc] init];
self.abVC.delegate = self;
}
- (void)addBillViewControllerDidAddOneBill {
NSLog(#"Added a bill.");
}
#end
As you can see, there is button in AddBillViewController, when the button is pressed, addBill method will be called, then the delegate method addBillViewControllerDidAddOneBill in HomeViewController should be called, however in fact, it doesn't.
I think you are not getting the reference right here in this line
self.abVC = [[AddBillViewController alloc] init];
If you are performing a segue, like the AddBillViewController is your next controller, set delegate in performSegue: function
like
AddBillViewController *vc = [segue destinationViewController];
[vc setDelegate:self];
I saw a lot of this kind of questions and answers here, but couldn't find solution to my problem. I'm trying to send data from one view controller to another and use delegate. But don't know why my postDelegate doesn't responds to selector. Is something wrong with this code or what is the problem?
PostViewController.h file
#protocol GetDataDelegate <NSObject>
-(void)getPassedInfo:(NSString*)info;
#end
#interface PostViewController : UIViewController
#property (nonatomic, weak) id <GetDataDelegate> postDelegate;
#end;
PostViewController.m file
#import "PostViewController.h"
- (IBAction)postData:(id)sender {
if ([_postDelegate respondsToSelector:#selector(getPassedInfo:)]) {
[self.postDelegate getPassedInfo:#"data"];
NSLog(#"responds");
}
[self dismissViewControllerAnimated:YES completion:nil];
}
in second view controllers .h file
#import "PostViewController.h"
#interface MainViewController : UITableViewController <GetDataDelegate>
and in .m file
#implementation MainWindowTableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
PostViewController * postController = [[PostViewController alloc]init];
postController.postDelegate = self;
}
and here is delegate method:
-(void)getPassedInfo:(NSString *)info{
NSLog(#"info is %#", info);
}
You need to make postController a property or an ivar. Currently it is a local variable in the viewDidLoad method which will be deallocated after viewDidLoad completes as #CodaFi said above.
#import "PostViewController.h"
#interface MainViewController : UITableViewController <GetDataDelegate>
#property (nonatomic, strong) PostViewController *postController;
#end
Then:
- (void)viewDidLoad
{
[super viewDidLoad];
self.postController = [[PostViewController alloc]init];
self.postController.postDelegate = self;
}
I have a protocol in one class:
#protocol DataStorageManager
- (void) saveFile;
#end
#interface DataManager : NSObject
{
id <DataStorageManager> delegate;
}
#property (nonatomic, assign) id<DataStorageManager> delegate;
//methods
#end
and its implementation:
#implementation DataManager
#synthesize delegate;
#end
and I have another class which is the adapter between the first and the third one:
#import "DataManager.h"
#import "DataPlistManager.h"
#interface DataAdapter : NSObject <DataStorageManager>
#property (nonatomic,strong) DataPlistManager *plistManager;
- (void) saveFile;
#end
and its implementation
#import "DataAdapter.h"
#implementation DataAdapter
-(id) initWithDataPlistManager:(DataPlistManager *) manager
{
self = [super init];
self.plistManager = manager;
return self;
}
- (void) saveFile
{
[self.plistManager savePlist];
}
#end
So when I in first method try to call my delegate method like this
[delegate saveFile];
Nothing happened. I don't understand what's wrong with the realization - it's a simple adapter pattern realization. So I need to use the delegate which will call the methods from the third class. Any help?
You are not setting the delegate property. You need to do this,
-(id) initWithDataPlistManager:(DataPlistManager *) manager
{
self = [super init];
self.plistManager = manager;
self.plistManager.delegate = self;
return self;
}
Also, in DataManager class remove the ivar declaration, just declaring property is sufficient, the ivar gets automatically created. Call the delegate method as below,
if([self.delegate respondsToSelector:#selector(saveFile)] {
[self.delegate saveFile];
}
Hope that helps!
In your case you forget to set your protocol delegate and also need to call protocol method
by self.delegate....
I just Give Basic Idea for how to Create Protocol
Also Read This Question
#DetailViewController.h
#import <UIKit/UIKit.h>
#protocol MasterDelegate <NSObject>
-(void) getButtonTitile:(NSString *)btnTitle;
#end
#interface DetailViewController : MasterViewController
#property (nonatomic, assign) id<MasterDelegate> customDelegate;
#DetailViewController.m
if([self.customDelegate respondsToSelector:#selector(getButtonTitile:)])
{
[self.customDelegate getButtonTitile:button.currentTitle];
}
#MasterViewController.m
create obj of DetailViewController
DetailViewController *obj = [[DetailViewController alloc] init];
obj.customDelegate = self;
[self.navigationController pushViewController:reportTypeVC animated:YES];
and add delegate method in MasterViewController.m for get button title.
#pragma mark -
#pragma mark - Custom Delegate Method
-(void) getButtonTitile:(NSString *)btnTitle;
{
NSLog(#"%#", btnTitle);
}
I have created a very basic application using the Utility Application template in Xcode 4.2 in which I want an integer variable obtained from a slider or text field in my FlipsideViewController available in my MainViewController.
I have been searching for hour on global variables but can't find a nice simple answer that works for my specific case.
Please help
(note: I am very new at developing for IOS and objective C. Dumb your answer down for me as much as you are capable!)
Thanks a lot
The following is a basic version of my code showing what I want to do.
FlipSideViewController.h
#import <UIKit/UIKit.h>
#class FlipsideViewController;
#protocol FlipsideViewControllerDelegate
- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller;
#end
#interface FlipsideViewController : UIViewController
#property (weak, nonatomic) id <FlipsideViewControllerDelegate> delegate;
- (IBAction)done:(id)sender;
- (IBAction)sliderChange:(id)sender;
#property (weak, nonatomic) IBOutlet UILabel *sliderValueOnFlipside;
#end
FlipSideViewController.m
#import "FlipsideViewController.h"
#interface FlipsideViewController ()
#end
#implementation FlipsideViewController
#synthesize sliderValueOnFlipside;
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidUnload
{
[self setSliderValueOnFlipside:nil];
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#pragma mark - Actions
- (IBAction)done:(id)sender
{
[self.delegate flipsideViewControllerDidFinish:self];
}
- (IBAction)sliderChange:(id)sender {
UISlider *slider = (UISlider *) sender;
int var = [slider value];
sliderValueOnFlipside.text = [NSString stringWithFormat:#"Slider Value is %d",var];
}
#end
MainViewController.h
#import "FlipsideViewController.h"
#interface MainViewController : UIViewController <FlipsideViewControllerDelegate>
- (IBAction)showInfo:(id)sender;
#property (weak, nonatomic) IBOutlet UILabel *sliderValueOnMain;
#end
MainViewController.m
#import "MainViewController.h"
#interface MainViewController ()
#end
#implementation MainViewController
#synthesize sliderValueOnMain;
- (void)viewDidLoad
{
[super viewDidLoad];
sliderValueOnMain.text = [NSString stringWithFormat:#"Slider Value from flipside is %d", var];
}
- (void)viewDidUnload
{
[self setSliderValueOnMain:nil];
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#pragma mark - Flipside View
- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller
{
[self dismissModalViewControllerAnimated:YES];
}
- (IBAction)showInfo:(id)sender
{
FlipsideViewController *controller = [[FlipsideViewController alloc] initWithNibName:#"FlipsideViewController" bundle:nil];
controller.delegate = self;
controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:controller animated:YES];
}
#end
I can easily get the value of the slider to be displayed on the flipside view however I also want that value displayed on the main view.
Global variables are generally frowned upon in polite programming circles.
If you want a method in MainViewController to react to a change in state in FlipsideViewController, then you could make MVC a delegate of FVC, and have FVC call a method on MVC when the value changes.
There's a good explanation of the delegate design pattern here: http://mobiledevelopertips.com/objective-c/the-basics-of-protocols-and-delegates.html