objective C [self init] hierarchy for multilevel inheritance - ios

I have class A which inherits class B. And want to achieve something like below. But the init methods get recursive call due to dynamic typecasting.
Is there any way to achieve such? Any suggestion? (without changing 'init's name in subclass?
#interface A : NSObject
#property NSData * data;
#end
#implementation A
- (id) init {
self = [super init];
/* want to do some default initialization here
for this class and all of its subclasses. */
// ... ...
return self;
}
/* This [self init] get recursed.
But how can I force this class and all of its subclass to call [self init] above,
not to call the subclass's init method. */
- (id) initWithData:(NSData *)d {
self = [self init];
self.data = d;
return self;
}
#end
#interface B : A
#end
#import "B.h"
#implementation B
- (id) init {
self = [super initWithData:nil];
// some subclass specific init code here ...
return
}
#end
Using B,
- (void) testInit{
B * b = [[B alloc] init];
}

You're calling [self init] in your implementation which is causing the recursion issue..
Implement this way :
- (id) init {
self = [super init];
//Basic empty init...
return self;
}
- (id) initWithData:(NSData *)d
{
self = [super init]; //<---- check this line.
if(self)
{
self.data = d;
}
return self;
}
//If you are looking to write some init code only 1 time the the following can work.....
-(void)oneTimeWrittenInitCode:(id)mySelf
{
//your init code which you wish to write one time goes here...
}
- (id) init {
self = [super init];
if(self)
{
[self oneTimeWrittenInitCode:self];
}
return self;
}
- (id) initWithData:(NSData *)d
{
self = [super init];
if(self)
{
[self oneTimeWrittenInitCode:self];
self.data = d;
}
return self;
}

Look up the "designated initializer" pattern. It describes how to arrange initializer methods and convenience constructors (a.k.a. factory methods) in a class hierarchy.

Here is an example of designated initilizer pattern mentioned above,
#import ”Person.h”
#implementation Person
-(id) initWithAge:(int)theAge AndHeight:(int)theHeight AndName:(NSString *)theName {
if (self = [super init]){
_age = theAge;
_height = thefleight;
_name = theName;
}
return self;
}
-(id) initwithAge:(int)theAge AndHeight:(int)theHeight {
return [self initWithAge:theAge AndHeight:theHeight AndName:nil];
}
-(id) initwithAge:(int)theAge {
return [self initWithAge:theAge AndHeight:0];
}
- (id)init {
return [self initwithAge:0];
}
#end

It should be:
- (instancetype) initWithData:(NSData *)d
{
if(self = [super init])
{
_data = d;
}
return self;
}

Related

How can I implement a UIViewcontroller thread safe singleton when I use storyboard?

I need that one ViewController of my app is a singleton. I'm using storyboard.
I used this code:
- (id)init
{
if (self = [super init]) {
}
return self;
}
static id s_singleton = nil;
+ (id) alloc {
if(s_singleton != nil)
return s_singleton;
return [super alloc];
}
- (id) initWithCoder:(NSCoder *)aDecoder {
if(s_singleton != nil)
return s_singleton;
self = [super initWithCoder:aDecoder];
if(self) {
s_singleton = self;
}
return self;
Maybe it is not thread safe because it creates two different instance of the class...
How can I resolve this problem?

Object-c How to call father method in father when being subclass

#interface Father : NSObject
-(void)show;
#end
#interface Child : Father
-(void)show;
#end
- (instancetype)init
{
self = [super init];
[self show];
return self;
}
- (void)show
{
NSLog(#"I am father");
}
#end
#implementation Child
- (instancetype)init
{
self = [super init];
[self show];
return self;
}
- (void)show
{
NSLog(#"I am child");
}
#end
- (void)viewDidLoad
{
Child *child = [[Child alloc] init];
}
Output:
I am child
I am child
From the code and output, we can see [self show] in father actually call [child show]. Is there a way to call father method in father when the method is overridden by child, In other words, Is there a way to choose to father method or child method.
#implementation Child
- (instancetype)init
{
self = [super init];
[self show];
return self;
}
- (void)show
{
NSLog(#"I am child");
[super show]; // This line call show method of father class
}
#end
- (void)viewDidLoad
{
Child *child = [[Child alloc] init];
}
Try above code.
Go through Objective-C doc https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithObjects/WorkingwithObjects.html
You Can Call Super class methods using
[super show]; //call this method from within child class
This method execution, calls the show method in Super Class(Father Class In our Case)
Hope this helps

Simple custom delegate not getting called

Let's see if you guys can find the error here... because I'm really stuck right now.
DBManager.h
#protocol DBManagerDelegate <NSObject>
#optional
- (void) managerDidFinishUpdating:(id)controller;
#end
#interface DBManager : NSObject
#property (strong, nonatomic) id <DBManagerDelegate> delegate;
- (id) init;
#end
DBManager.m
#import "DBManager.h"
#implementation DBManager
- (id)init {
self = [super init];
if (self) {
[[self delegate] managerDidFinishUpdating:self];
}
return self;
}
UIViewController.h
#import <UIKit/UIKit.h>
#import "DBManager.h"
#interface DBViewController : UIViewController <DBManagerDelegate>
#property (nonatomic, retain) DBManager *manager;
#end
UIViewController.m
#import "DBViewController.h"
#implementation DBViewController
- (void)viewDidLoad
{
[super viewDidLoad];
_manager = [[DBMataroManager alloc] init];
[_manager setDelegate:self];
}
- (void)managerDidFinishUpdating:(id)controller {
NSLog(#"Manager did finish");
}
#end
You should write like this,
- (id)initWithDelegate:(id)delegate {
self = [super init];
if (self) {
_delegate = delegate;
[_delegate managerDidFinishUpdating:self];
}
return self;
}
//Call it as follow
_manager = [[DBManager alloc] initWithDelegate:self];
[_manager setDelegate:self];
The delegate method managerDidFinishUpdating: is called within init. You set yourself as the delegate after calling init.
Maybe an initWithDelegate: method would help.
- (instancetype)initWithDelegate:(id< DBManagerDelegate>)delegate {
self = [super init];
if (self) {
self.delegate = delegate;
[self.delegate managerDidFinishUpdating:self];
}
return self;
}
You are trying to use the delegate in the init, but you have not set it until the next statement. The only way to do this would be to set the delegate as part of you init statement.
-(id)initWithDelegate:(id<DBManageDelegate>)delegate {
if ((self = [super init])) {
self.delegate = delegate;
if (delegate && [delegate respondsToSelector:#selector(managerDidFinishUpdating:)]) {
[delegate performSelector:#selector(managerDidFinishUpdating:) withObject:self];
}
}
return self;
}
But if you plan to do some additional things before the manager is updated I would suggest you move all of that outside of the init, perhaps into an updateManager function like this
-(void)updateManager {
// Do the stuff that updates your manager here
if (delegate && [delegate respondsToSelector:#selector(managerDidFinishUpdating:)]) {
[delegate performSelector:#selector(managerDidFinishUpdating:) withObject:self];
}
}
..later in your app
_manager = [[DBMataroManager alloc] init];
[_manager setDelegate:self];
[_manager updateManager];

Code and encode UIView and UIViewController

Good day, everyone!
I have some view in scrollView. I want to save that views into file and then when app is open load it. So i have thias code:
-(void) encodeWithCoder:(NSCoder *)_coder{
[_coder encodeObject:self.currentForecast forKey:#"currentForecast"];
[_coder encodeObject:self.weatherForecastView forKey:#"weatherForecastView"];
[_coder encodeObject:self forKey:#"self"];
[_coder encodeObject:self.view forKey:#"view"];
}
-(id) initWithCoder:(NSCoder *)aDecoder{
self = [super init];
if (self) {
self.currentForecast = [aDecoder decodeObjectForKey:#"currentForecast"];
self.weatherForecastView = [aDecoder decodeObjectForKey:#"weatherForecastView"];
self.view = [aDecoder decodeObjectForKey:#"view"];
self = [aDecoder decodeObjectForKey:#"self"];
}
return self;
}
it works, but it looks like a screenshot of the views. How to live them up?
If it works, then why not just simplify like the following (remove the retain if you use ARC):
-(void) encodeWithCoder:(NSCoder *)_coder{
[_coder encodeObject:self forKey:#"self"];
}
-(instanceType) initWithCoder:(NSCoder *)aDecoder{
self = [[aDecoder decodeObjectForKey:#"self"] retain];
return self;
}
But I don't think it really works because using initWithCoder for self prevents calling [self init]. Or you can try:
-(instanceType) initWithCoder:(NSCoder *)aDecoder{
self = [[aDecoder decodeObjectForKey:#"self"] init];
return self;
}
But what is more common is to not encode self and that means:
-(void) encodeWithCoder:(NSCoder *)_coder{
[_coder encodeObject:self.view forKey:#"view"];
...
}
-(instanceType) initWithCoder:(NSCoder *)aDecoder{
self = [super init];
if (!self)
return nil;
self.view = [aDecoder decodeObjectForKey:#"view"];
...
return self;
}

Keeps giving me incorrect implementation with my singleton

I decided to try and make a Singleton for use with locations. I have got what I think to be, the singleton working correctly however I have one error that is now appearing. It tells me that my implementation is incomplete. It is the only error it is giving me and I am sure it is something wrong with either my view header or m file. I have tried a few things now and cannot get it to work. What am I missing here?
Here is my header
#import <UIKit/UIKit.h>
#interface TrackerViewController : UIViewController
-(void) locationUpdate;
end
And here is my implementation file:
#import "TrackerViewController.h"
#import "MyLocation.h"
#implementation TrackerViewController
NSString *LatCoord;
NSString *LongCoord;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
[LocationController sharedInstance].locDelegate = (id)self;
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (void)locationUpdate:(CLLocation *)location {
[[LocationController sharedInstance] setLocation:location];
LatCoord = [NSString stringWithFormat:#"%lf", location.coordinate.latitude];
LongCoord = [NSString stringWithFormat:#"%lf", location.coordinate.longitude];
}
- (BOOL)shouldAutorotateToInterfaceOrientation (UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return YES;
}
-(IBAction)CheckIn:(id)sender
{
[self locationUpdate];
}
#end
My singleton header is as follows:
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#protocol LocationControllerDelegate <NSObject>
#required
- (void)locationUpdate:(CLLocation*)location;
#end
#interface LocationController : NSObject <CLLocationManagerDelegate> {
__unsafe_unretained id <LocationControllerDelegate> _locDelegate;
CLLocationManager* locationManager;
CLLocation* location;
id locDelegate;
}
#property (nonatomic, retain) CLLocationManager* locationManager;
#property (nonatomic, retain) CLLocation* location;
#property (nonatomic, assign) id <LocationControllerDelegate> locDelegate;
+ (LocationController*)sharedInstance;
#end
My singleton implementation is as follows:
#import "MyLocation.h"
static LocationController* sharedCLDelegate = nil;
#implementation LocationController
#synthesize locationManager, location, locDelegate = _locDelegate;
- (id)init
{
self = [super init];
if (self != nil) {
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
}
return self;
}
- (void)dealloc
{
/* ... */
}
#pragma mark -
#pragma mark CLLocationManagerDelegate Methods
- (void)locationManager:(CLLocationManager*)manager
didUpdateToLocation:(CLLocation*)newLocation
fromLocation:(CLLocation*)oldLocation
{
/* ... */
}
- (void)locationManager:(CLLocationManager*)manager
didFailWithError:(NSError*)error
{
/* ... */
}
#pragma mark -
#pragma mark Singleton Object Methods
+ (LocationController*)sharedInstance {
#synchronized(self) {
if (sharedCLDelegate == nil) {
}
}
return sharedCLDelegate;
}
+ (id)allocWithZone:(NSZone *)zone {
#synchronized(self) {
if (sharedCLDelegate == nil) {
sharedCLDelegate = [super allocWithZone:zone];
return sharedCLDelegate;
}
}
return nil;
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
#end
What am I missing or doing wrong here?
I think the root of the problem is here:
#protocol LocationControllerDelegate <NSObject>
#required
- (void)locationUpdate:(CLLocation*)location;
#end
So you've defined a protocol with a required method, but unless I've missed it you haven't implemented that method anywhere in the object that adopts that protocol. The compiler is warning you that you haven't implemented all the required methods of the protocol.
Your singleton looks wrong. Your sharedInstance method should be:
+ (LocationController*)sharedInstance {
#synchronized(self) {
if (sharedCLDelegate == nil) {
sharedCLDelegate = [[self alloc] init];
}
}
return sharedCLDelegate;
}
And you can get rid of the allocWithZone: and copyWithZone: methods - they don't do anything useful.
That's most likely why your class isn't working, but probably has nothing to do with the "incomplete implementation" warning. The warning will be because you've forgotten to implement a method that's declared in your header or in one of your protocols, or maybe you've misspelled it. I couldn't spot it on a first pass, but I'll take another look.
If you double-click on the yellow warning icon in the header it should tell you which method hasn't been implemented properly.
By the way, the line below leaks because you're double-retaining (init sets retain count to one, and then assigning to a retained property sets it to 2). You should run the Analyze function, which will add blue warnings for leaks like this.
self.locationManager = [[CLLocationManager alloc] init];
Do one of the following instead:
//assign directly to the ivar so the setter method isn't used
locationManager = [[CLLocationManager alloc] init];
Or
//autorelease before assigning
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
locationUpdate is declared in your interface, but not defined in the implementation. locationUpdate: is defined -- close, but not quite.
Note: The message could have saved some time.

Resources