Constructor in Objective-C - objective-c

I was trying this sample program below.
I'm not calling the +(void)initialise and -(id)init method in the class B.But its getting called automatically.
Is the -(void)initialise is equal to the default constructor in objective C.
Does the [super init] points to the NSObject.
If i'm not using the -(id)init method i'm getting a warning that the class is with incomplete implementation.
ClassA.h
#import <Foundation/Foundation.h>
static int ab;
#interface ClassA : NSObject {
int a;
}
+ (void) initialize;
- (id) init;
- (void) displayNumOfInstance;
- (void) disp;
#end
ClassA.m
#import "ClassA.h"
#implementation ClassA
+ (void) initialize
{
ab=0;
}
- (id) init
{
self = [super init];
if (self!=nil) {
ab++;
}
return self;
}
- (void) displayNumOfInstance
{
NSLog(#"Number of instances of this class:%d",ab);
}
- (void) disp
{
NSLog(#"The value is %d",ab);
}
#end
ClassB.h
#import <Foundation/Foundation.h>
#import "ClassA.h"
#interface ClassB : ClassA {
}
- (void) display;
#end
ClassB.m
#import "ClassB.h"
#implementation ClassB
- (void) display
{
ab=20;
NSLog(#"The value ab is %d",ab);
}
#end
class2.m
#import <Foundation/Foundation.h>
#import "ClassA.h"
int main (int argc, const char * argv[]) {
ClassA *a = [[ClassA alloc]init];
[a disp];
[a release];
ClassB *b = [[ClassB alloc]init];
[b display];
[b release];
ClassA *a1 = [[ClassA alloc]init];
[a1 disp];
[a1 release];
ClassB *b1 = [[ClassB alloc]init];
[b1 display];
[b1 release];
return 0;
}
Output:
2011-04-30 15:31:42.490 class2[1674:a0f] 1
2011-04-30 15:31:42.493 class2[1674:a0f] The value ab is 20
2011-04-30 15:31:42.494 class2[1674:a0f] 2
2011-04-30 15:31:42.495 class2[1674:a0f] The value ab is 20

The default construction usually start with has the following format -init or any variant upon this, e.g. -initWithFrame:.
The method +initialize is a class method (static method) that's called at least once when your application starts. You can use this method to initialize static variables that are useful across all instances of the class. This method might be useful to e.g. initialize a shared cache or a shared lookup map for a class.
For NSObject the -init method is the designated initializer, but for other classes this might differ. Apple documents the designated initializer in it's class headers using the NS_DESIGNATED_INITIALIZER macro. For example UIView subclasses should override -initWithFrame: and -initWithCoder: instead, as these methods are marked as designated initializer.
When subclassing and implementing a custom designated initializer, don't forget to initialize the super class as well. Let's for example have a UIView subclass that has a custom designated initializer -initWithFrame:title:. We would implement it as follows:
// A custom designated initializer for an UIView subclass.
- (id)initWithFrame:(CGRect)frame title:(NSString *)title
{
// Initialize the superclass first.
//
// Make sure initialization was successful by making sure
// an instance was returned. If initialization fails, e.g.
// because we run out of memory, the returned value would
// be nil.
self = [super initWithFrame:frame];
if (self)
{
// Superclass successfully initialized.
self.titleLabel.text = title
}
return self;
}
// Override the designated initializer from the superclass to
// make sure the new designated initializer from this class is
// used instead.
- (id)initWithFrame:(CGRect)frame
{
return [[self alloc] initWithFrame:frame title:#"Untitled"];
}
More details on initialising can be found on the Apple Developer website:
Object Initialization
Multiple Initializers

Related

Why is it ok instantiatie self from a super init method?

I was doing some coding where I had a class MyClass which inherits from class MySuperClass. MyClass has a property myProperty.
So I was creating an instance of this class from JSON and in a moment of thoughtlessness I wrote my method like this:
+ (instancetype)newFromJSON:(NSDictionary *)json {
MyClass *myObject = [super newFromJSON:json];
myObject.myProperty = someValue;
return myObject;
}
Note that MySuperClass does have a method + (instancetype)newFromJSON:(NSDictionary *)json.
Now, this obviously doesn't work since the call to super newFromJSON will return an instance of MySuperClass which would become the actual type of myObject. This will of course give me a runtime error since MySuperClass doesn't have a myProperty property.
But this got me thinking about something. Why are we able to do seemingly the same thing when we are instantiating objects with a call to [super init]?
Why is it ok to do this:
- (instancetype)init {
self = [super init];
if (self) {
self.myProperty = someValue;
}
return self;
}
Is it because init methods are treated specially in this regard like they are in so many other? Or is it perhaps that assigning to selfchanges the actual type in a way that does not happen when assigning to a regular variable?
The super keyword only indicates from where in the inheritance chain to start looking to find the selector (method) you are invoking. It says to start looking at the current instance's superclass, instead of the instance's class.
What it does not do is change the class type of the self parameter implicitly passed to a method.
Thus, when invoking [super init], the init implementation in the superclass still receives a reference to MySubClass (or whatever).
Note: you can find documentation which states that init may return a different class than the one on which it was invoked. This is common for class clusters. This is because the idiomatic implementation of init simply returns self without constructing a new instance, but it's allowed to.
A few points of clarification:
+ (instancetype)newFromJSON:(NSDictionary *)json {
MyClass *myObject = [super newFromJSON:json];
myObject.myProperty = someValue;
return myObject;
}
When you invoke [super newFromJSON:json], all you are doing is telling the Objective-C runtime to start the search for the method newFromJSON: from self's superclass.
It is not changing the class self.
So, yes, that code is correct and will work fine.
Furthermore, there is absolutely nothing special about the init method and its treatment of super.
There is a bit of a difference in when you are doing + (instancetype)newFromJSON:(NSDictionary *)json versus init. The former is doing both an allocation of memory and initialization of the new instance. init is solely doing the initialization of the instance.
init is special during compilation, in that it does expect you to call [super init] (it will warn you). But effectively it is saying "use my superclass to initialize me first".
Note to do what you want is possible. You just need to have the superclass modify how it allocates memory. You need to do something like:
Parent *myObject = [[[super class] alloc] init];
Here is a code example to hopefully illustrate these points.
Let's say you have these classes:
#interface Parent : NSObject
#property (nonatomic, assign) NSInteger someValue;
+ (instancetype)newInstance;
- (instancetype)init;
#end
#implementation Parent
+ (instancetype)newInstance {
Parent *myObject = [[[super class] alloc] init];
NSLog(#"Creating new item of class %#", NSStringFromClass([myObject class]));
return myObject;
}
- (instancetype)init {
// This [super init] calls NSObject's init
self = [super init];
if (self) {
_someValue = 1000;
}
return self;
}
#end
#interface ClassA : Parent
#property (nonatomic, assign) NSInteger otherValue;
#end
#implementation ClassA
+ (instancetype)newInstance {
ClassA *myObject = [super newInstance];
myObject.otherValue = 2000;
return myObject;
}
- (instancetype)init {
// This [super init] calls ClassA's init
self = [super init];
if (self) {
}
return self;
}
#end
#interface ClassB : Parent
#end
#implementation ClassB
// Default init will be Parent's
#end
#interface ClassC : Parent
#end
#implementation ClassC
- (instancetype)init {
// We are not calling [super init];
// NOTE: This will yield a warning since we are not calling super
return self;
}
#end
If you execute:
ClassA *classA = [[ClassA alloc] init];
ClassB *classB = [[ClassB alloc] init];
ClassC *classC = [[ClassC alloc] init];
Parent *newInstanceParent = [Parent newInstance];
ClassA *newInstanceClassA = [ClassA newInstance];
NSLog(#"classA.someValue = %ld, classB.someValue = %ld, classC.someValue = %ld", classA.someValue, classB.someValue, classC.someValue);
NSLog(#"classA.otherValue = %ld, newInstanceClassA.otherValue = %ld", classA.otherValue, newInstanceClassA.otherValue);
NSLog(#"newInstanceParent is %#, newInstanceClassA is %#", NSStringFromClass([newInstanceParent class]), NSStringFromClass([newInstanceClassA class]));
You'll get output of:
Creating new item of class Parent
Creating new item of class ClassA
classA.someValue = 1000, classB.someValue = 1000, classC.someValue = 0
classA.otherValue = 0, newInstanceClassA.otherValue = 2000
newInstanceParent is Parent, newInstanceClassA is ClassA

Objective-C Runtime - Run Code at Deallocation of Any Object

I was reading this article by Jeff Kelley and trying to do the same. However the code was written before ARC was adopted and now fails to compile.
http://blog.slaunchaman.com/2011/04/11/fun-with-the-objective-c-runtime-run-code-at-deallocation-of-any-object/
The main problem is in this part of the printout, some casting errors and then blocked release messages. I found it to be a very interesting example but I can't seem to get it to work.
The problems are:
0. Autosynthesized property 'block' will use synthesized instance variable '_block', not existing instance variable 'block' on the #implementation JKBlockExecutor
1. Cast of block pointer type 'voidBlock' (aka 'void (^)(void)') to C pointer type 'const void *' requires a bridged cast and Cast of C pointer type 'void *' to block pointer type 'typeof (aBlock)' (aka 'void (^__strong)(void)') requires a bridged cast" on the block = Block_copy(aBlock); line
2. Cast of block pointer type 'voidBlock' (aka 'void (^)(void)') to C pointer type 'const void *' requires a bridged cast on Block_release(block);
typedef void (^voidBlock)(void);
#interface JKBlockExecutor : NSObject {
voidBlock block;
}
#property (nonatomic, readwrite, copy) voidBlock block;
- (id)initWithBlock:(voidBlock)block;
#end
#implementation JKBlockExecutor
#synthesize block;
- (id)initWithBlock:(voidBlock)aBlock
{
self = [super init];
if (self) {
block = Block_copy(aBlock);
}
return self;
}
- (void)dealloc
{
if (block != nil) {
block();
Block_release(block);
}
[super dealloc];
}
#end
This is where he creates a category on NSObject.
const void *runAtDeallocBlockKey = &runAtDeallocBlockKey;
#interface NSObject (JK_RunAtDealloc)
- (void)runAtDealloc:(voidBlock)block;
#end
#implementation NSObject (JK_RunAtDealloc)
- (void)runAtDealloc:(voidBlock)block
{
if (block) {
JKBlockExecutor *executor = [[JKBlockExecutor alloc] initWithBlock:block];
objc_setAssociatedObject(self,
runAtDeallocBlockKey,
executor,
OBJC_ASSOCIATION_RETAIN);
[executor release];
}
}
#end
This is how you execute the example.
NSObject *foo = [[NSObject alloc] init];
[foo runAtDealloc:^{
NSLog(#"Deallocating foo!");
}];
[foo release];
Or another way to get other information.
NSObject *foo = [[NSObject alloc] init];
__block id objectRef = foo;
[foo runAtDealloc:^{
NSLog(#"Deallocating foo at address %p!", objectRef);
}];
[foo release];
Can this code be fixed somehow? I took out all the release messages to no avail.
Code below builds and works (or at least seems so), and prints "Deallocating foo!" when I expect it to print it. Part 1:
typedef void (^voidBlock)(void);
#interface JKBlockExecutor : NSObject {
voidBlock block;
}
#property (nonatomic, readwrite, copy) voidBlock block;
- (id)initWithBlock:(voidBlock)block;
#end
#implementation JKBlockExecutor
#synthesize block = block;
- (id)initWithBlock:(voidBlock)aBlock
{
self = [super init];
if (self) {
block = [aBlock copy];
}
return self;
}
- (void)dealloc
{
if (block != nil) {
block();
block = nil;
}
}
#end
Part 2:
const void *runAtDeallocBlockKey = &runAtDeallocBlockKey;
#interface NSObject (JK_RunAtDealloc)
- (void)runAtDealloc:(voidBlock)block;
#end
#implementation NSObject (JK_RunAtDealloc)
- (void)runAtDealloc:(voidBlock)block
{
if (block) {
JKBlockExecutor *executor = [[JKBlockExecutor alloc] initWithBlock:block];
objc_setAssociatedObject(self,
runAtDeallocBlockKey,
executor,
OBJC_ASSOCIATION_RETAIN);
}
}
#end
Testing if it works:
#autoreleasepool {
NSObject *foo = [[NSObject alloc] init];
[foo runAtDealloc:^{
NSLog(#"Deallocating foo!");
}];
}
EDIT
Changed Block_release(block); to block = nil;
If you want to know more about the code below ,please go to Fun With the Objective-C Runtime: Run Code at Deallocation of Any Object
Part 1:create one class: the object We Want To Be Released When That Happens--- this class is like an event:when the target obj dealloc,it happens。use block to execute the event 。
// .m file
// http://weibo.com/luohanchenyilong/
// https://github.com/ChenYilong
// the object We Want To Be Released When That Happens--- this class is like an event:when the target obj dealloc,it happens。use block to execute the event 。
typedef void (^voidBlock)(void);
#interface CYLBlockExecutor : NSObject
- (id)initWithBlock:(voidBlock)block;
#end
// .m file
// http://weibo.com/luohanchenyilong/
// https://github.com/ChenYilong
// the object We Want To Be Released When That Happens--- this class is like an event:when the target obj dealloc,it happens。use block to execute the event 。
#import "CYLBlockExecutor.h"
#interface CYLBlockExecutor() {
voidBlock _block;
}
#implementation CYLBlockExecutor
- (id)initWithBlock:(voidBlock)aBlock
{
self = [super init];
if (self) {
_block = [aBlock copy];
}
return self;
}
- (void)dealloc
{
_block ? _block() : nil;
}
#end
Part 2:core code:use runtime to realize cyl_runAtDealloc method
// CYLNSObject+RunAtDealloc.h file
// http://weibo.com/luohanchenyilong/
// https://github.com/ChenYilong
// use runtime to realize cyl_runAtDealloc method
#import "CYLBlockExecutor.h"
const void *runAtDeallocBlockKey = &runAtDeallocBlockKey;
#interface NSObject (CYLRunAtDealloc)
- (void)cyl_runAtDealloc:(voidBlock)block;
#end
// CYLNSObject+RunAtDealloc.m file
// http://weibo.com/luohanchenyilong/
// https://github.com/ChenYilong
// use runtime to realize cyl_runAtDealloc method
#import "CYLNSObject+RunAtDealloc.h"
#import "CYLBlockExecutor.h"
#implementation NSObject (CYLRunAtDealloc)
- (void)cyl_runAtDealloc:(voidBlock)block
{
if (block) {
CYLBlockExecutor *executor = [[CYLBlockExecutor alloc] initWithBlock:block];
objc_setAssociatedObject(self,
runAtDeallocBlockKey,
executor,
OBJC_ASSOCIATION_RETAIN);
}
}
#end
How to use :
#import "CYLNSObject+RunAtDealloc.h"
then
NSObject *foo = [[NSObject alloc] init];
[foo cyl_runAtDealloc:^{
NSLog(#"Deallocating foo!");
}];

Setting Other Class Variable

I have 2 classes, ClassA and ClassB
ClassA has one BOOL variable set to No.
I am trying to set this variable to Yes from ClassB, but can't seem to figure out how to.
Below is the code I am using which doesn't work, it is simply what I would've thought would work, I have stripped out the unnecessary information:
Class A:
ClassA.h
#interface AppDelegate : NSObject <NSApplicationDelegate> {
BOOL boolean;
}
- (id) init;
ClassA.m
- (id) init {
boolean = NO;
}
Class B:
ClassB.h
#import "ClassA.h"
- (IBAction) setBoolean: (id)sender;
ClassB.m
- (id) init {
ClassA * theClassA = [[ClassA alloc] init];
return self;
}
- (IBAction) setBoolean: (id)sender {
[theClassA boolean] = YES;
}
I hope this makes sense. I simply want to set the BOOL boolean in ClassA to YES from ClassB.
You can't assign a property like that ([object property] = value). The proper syntax is [object setProperty:value] or object.property = value.
I wouldn't call a variable boolean. Might be misleading. Even though it's not the keyword for a boolean variable in Objective-C it is in a lot of other languages.
And you have to return the initialized object (self) in your init method (you have an id return type, not void):
- (id) init {
self = [super init];
if (self) {
boolean = NO;
}
return self;
}
Also, you didn't specify an instance variable for theClassA in your ClassB implementation. You just create a local object and then leak it (you don't release it). Instead, declare it in your ClassB.h:
#class ClassA;
#interface ClassB : NSObject {
ClassA *theClassA;
}
- (IBAction)setBoolean:(id)sender;
#end
Then initialize it like this:
- (id) init {
self = [super init];
if (self) {
theClassA = [[ClassA alloc] init];
}
return self;
}
And don't forget to release it in dealloc:
- (void)dealloc {
[theClassA release];
[super dealloc];
}
And one last thing. Having a method - (IBAction) setBoolean: (id)sender in your ClassB implies that ClassB has a property called boolean, which is not the case. I recommend renaming that method and/or rethinking your class designs.

Why This Class <Not Responding>

Hi
i dont know why i call a function in "msg" class
it has no respond:(
this is the "msg" class:
msg.h :
#import <UIKit/UIKit.h>
#interface msg : NSObject {
}
-(void) Print;
#end
msg.m :
#import "msg.h"
#implementation msg
-(void) Print {
NSLog(#"Hello World");
}
#end
viewController.h :
#import <UIKit/UIKit.h>
#import "msg.h"
#class msg;
#interface ClassMod4ViewController : UIViewController {
msg *object;
}
#property (nonatomic,retain) msg *object;
#end
viewController.m :
#import "ClassMod4ViewController.h"
#implementation ClassMod4ViewController
#synthesize object;
- (void)viewDidLoad {
[object Print];
[super viewDidLoad];
}
Thanks
Was the object initialized in the designated initializer (usually initWithNibName:bundle: for UIViewController subclasses) prior to viewDidLoad being invoked?
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
// ...
object = [[Msg alloc] init];
// ...
return self;
}
If the object has not been initialized, then it's nil. Remember that it's okay to send nil objects messages in Objective-C (nothing will happen as a result).
have you tried:
- (void)viewDidLoad {
assert(object);
[object Print];
[super viewDidLoad];
}
?
if the assertion fails, then the pointer to object is 0 (or nil). you must create the object before you use it. this is typically performed in the initializer (in your case, of the class that contains the instance of object):
- (id)init {
self = [super init];
if (0 != self) {
object = [[msg alloc] init];
}
return self;
}
but sometimes you'll want to create the object later on.
if you are initializing it, then you may want to set breakpoints where the object is accessed in order to determine where the object is set to 0.

Why can't I initialize a class through a setter?

If I have a custom class called Tires:
#import <Foundation/Foundation.h>
#interface Tires : NSObject {
#private
NSString *brand;
int size;
}
#property (nonatomic,copy) NSString *brand;
#property int size;
- (id)init;
- (void)dealloc;
#end
=============================================
#import "Tires.h"
#implementation Tires
#synthesize brand, size;
- (id)init {
if (self = [super init]) {
[self setBrand:[[NSString alloc] initWithString:#""]];
[self setSize:0];
}
return self;
}
- (void)dealloc {
[super dealloc];
[brand release];
}
#end
And I synthesize a setter and getter in my View Controller:
#import <UIKit/UIKit.h>
#import "Tires.h"
#interface testViewController : UIViewController {
Tires *frontLeft, *frontRight, *backleft, *backRight;
}
#property (nonatomic,copy) Tires *frontLeft, *frontRight, *backleft, *backRight;
#end
====================================
#import "testViewController.h"
#implementation testViewController
#synthesize frontLeft, frontRight, backleft, backRight;
- (void)viewDidLoad {
[super viewDidLoad];
[self setFrontLeft:[[Tires alloc] init]];
}
- (void)dealloc {
[super dealloc];
}
#end
It dies after [self setFrontLeft:[[Tires alloc] init]] comes back. It compiles just fine and when I run the debugger it actually gets all the way through the init method on Tires, but once it comes back it just dies and the view never appears. However if I change the viewDidLoad method to:
- (void)viewDidLoad {
[super viewDidLoad];
frontLeft = [[Tires alloc] init];
}
It works just fine. I could just ditch the setter and access the frontLeft variable directly, but I was under the impression I should use setters and getters as much as possible and logically it seems like the setFrontLeft method should work.
This brings up an additional question that my coworkers keep asking in these regards (we are all new to Objective-C); why use a setter and getter at all if you are in the same class as those setters and getters.
You have declared frontLeft as a 'copy' property:
#property (nonatomic,copy) Tires *frontLeft, *frontRight, *backleft, *backRight;
When you assign to this property, a copy is made by invoking the object's copy method. This only works for objects which support the NSCopying protocol (i.e., which implement a copyWithZone: method). Since your Tires class does not implement this method, you get an exception.
You probably want to change this to be a 'retain' property:
#property (nonatomic,retain) Tires *frontLeft, *frontRight, *backleft, *backRight;
See the Objective C documentation on declared properties for more on property declarations.
One problem that i see is here:
- (void)viewDidLoad {
[super viewDidLoad];
[self setFrontLeft:[[Tires alloc] init]];
}
When you call [Tires alloc] you get back an object with a retain count of 1. You then use a set method which you have synthesized, which bumps the retain count to 2. When your object is done with the Tire object, it will reduce the retain count back to 1, but the tire will never get deallocated. I think you should use:
[self setFrontLeft:[[[Tires alloc] init] autorelease]];