Suppose I have a parent init method like so:
- (id)initWithValue:(int)val name:(NSString *)n
{
value = val;
name = n;
}
and a child class with an init like so:
- (id)initWithAge:(int)a
{
age = a;
}
Is there a way to do the following:
[Child initWithAge:10 value:12 name:#"Sam"];
where the age will go to the child init method and the "value" and "name" go to the parent method? Or does every child have to expect all arguments it expects and pass it to the parent using [super init]??
- (id)initWithAge:(int)a value:(int)val name:(NSString *)n
{
self = [super initWithValue:val name:n];
if(self)
{
age = a;
}
return self;
}
In Child, you would have to declare initWithAge: value: name:. Nothing will "go to the parent" method explicitly without some work on your part.
You would declare amethod in Child:
-(id)initWithAge:(int)age value:(iint)value name:(NSString*)name {
if ( (self = [super initWithValue:value name:name]) ) {
_age = age; // assuming you an ivar '_age'
}
return self;
}
You can pass certain things on to the super class, but only what it is expecting, nothing will create methods for you.
Have read on inheritance and polymorphism, and it important to understand what self is.
Related
I am using 2 nsobject class ,
First nsobject class some property and it holds some values.
In Second NSObject class i want to access the first nsobject class properties.
I have tried little bit ,it showing null values
Here is my code
My First NSObject class
FieldData.M
-(instancetype)initWithDictionary:(NSDictionary *)dictFieldData
{
if (self = [super init]) {
///set the field id
self.fieldId = [[dictFieldData objectForKey:#"f_id"]intValue];
self.display = [[dictFieldData objectForKey:#"f_display"]boolValue];
self.fieldLength = [[dictFieldData objectForKey:#"f_length"]intValue];
self.mandatory = [[dictFieldData objectForKey:#"f_mandatary"]boolValue];
self.strFieldLabel = [dictFieldData objectForKey:#"f_label"];
NSString *strFieldAttrib = [dictFieldData objectForKey:#"f_attribute"];
if ([strFieldAttrib.lowercaseString isEqualToString:#"alpha"]) {
self.fieldAttribute = FieldAttributeAlpha;
}
else if ([strFieldAttrib.lowercaseString isEqualToString:#"numeric"]) {
self.fieldAttribute = FieldAttributeNumeric;
}
else if ([strFieldAttrib.lowercaseString isEqualToString:#"alpha_numeric"]) {
self.fieldAttribute = FieldAttributeAlphaNumeric;
}
}return self;
}
****Second NSObjectClass**
SiteData.m**
-(instancetype)initWithDictionary:(NSDictionary *)dictSiteData
{
self.fieldData = [FieldData new];
if (self = [super init]) {
self.siteId = [[dictSiteData objectForKey:#"s_id"]intValue];
self.siteName = [dictSiteData objectForKey:#"site_name"];
NSLog(#"%d",self.fieldData.fieldId);
}
return self;
}
Please anyone helpme to do this
Please what i am doing wrong
Thanks in Advance !!!
Please write this code in Appdelegate declare this property.
After that SetValue your Dictionary Data
#property(strong,nonatomic)NSDictionary * dictFieldData;
Write this code My First NSObject class FieldData.M
Create object in ViewdidLoad
AppDelegate *appdelegate ((AppDelegate *)[[UIApplication sharedApplication] delegate]);
///set the field id
self.fieldId = [[appdelegate.dictFieldData SetValue:(NSString*) objectForKey:#"f_id"]intValue];
///Get the field id
self.siteId = [[appdelegate.dictSiteData Valueforkey:#"s_id"]intValue];
NSLog(#"%d",appdelegate.dictSiteData);
Check this post answer for Accessing Property from another NSObjectClass
[FieldData new] will by default invoke the init method, not the initWithDictionary one. Unless you've defined init to set values for your property it will default to nil. You probably need to create your object using [[FieldData alloc] initWithDictionary:...] (or [FieldData newWithDictionary:...] if you've defined that method). HTH
I have a class A. B inherits A. Both classes implement method1 and method2.
method1 in A calls method2. It look like...
- (void)method1{
// some code
[self method2];
// some code
}
- (void)method2{
// some work
}
method1 in B calls super class method 1, and B also overrides method2.
- (void)method1{
[super method1];
}
- (void)method2{
// some work
}
Now, when B's instance is created and called method1 A's method1 calls method2 in B. What I want to do is calling A's method2 from A's method1 even when it is called from child(B).
In other words, in A's method1, I want to "forcefully" call the method in the same owner(class).
Is there any easy way to do it? I think I can do it with calling objective-c runtime functions but I want to know if there is easier way.
I know that this is not the design we should make in usual case, but from a little complex reason I have to do it. So please don't propose me to change the design or ask me what is the original goal of the program.
As a simplest solution I can come up with, use BOOL flag to decide how method2 should behave:
#interface B ()
#property (nonatomic) BOOL shouldCallSuperMethod2;
#end
#implementation B
- (void)method1{
self.shouldCallSuperMethod2 = YES;
[super method1];
self.shouldCallSuperMethod2 = NO;
}
- (void)method2{
if (self.shouldCallSuperMethod2) {
[super method2];
}
else {
// some work
}
}
#end
Note that this solution is not thread safe.
UPD Another interesting way, using runtime magic:
#import ObjectiveC.runtime;
#implementation B
- (void)method2 {
NSUInteger returnAddress = (NSUInteger)__builtin_return_address(0);
NSUInteger callerIMPAddress = 0;
SEL interestingSelector = #selector(method1);
// Iterate over the class and all superclasses
Class currentClass = object_getClass(self);
while (currentClass)
{
// Iterate over all instance methods for this class
unsigned int methodCount;
Method *methodList = class_copyMethodList(currentClass, &methodCount);
unsigned int i;
for (i = 0; i < methodCount; i++)
{
// Ignore methods with different selectors
if (method_getName(methodList[i]) != interestingSelector)
{
continue;
}
// If this address is closer, use it instead
NSUInteger address = (NSUInteger)method_getImplementation(methodList[i]);
if (address < returnAddress && address > callerIMPAddress)
{
callerIMPAddress = address;
}
}
free(methodList);
currentClass = class_getSuperclass(currentClass);
}
if (callerIMPAddress == (NSUInteger)[self methodForSelector:interestingSelector]) {
// method2 is called from method1, call super instead
[super method2];
}
else {
// some work
}
}
#end
Other interesting ways to identify caller may be found in answers to this question
I wonder is there any drawbacks when use alloc/free with pure C array inside Objective-C class?
For example:
#import "CVPatternGrid.h"
#implementation CVPatternGrid
#synthesize row = _row;
#synthesize column = _column;
#synthesize count = _count;
#synthesize score = _score;
- (id)initWithRow:(NSInteger)row column:(NSInteger)column {
if (self = [super init]) {
_grid = [self allocateNewGrid:row column:column];
}
return self;
}
- (NSInteger)moveCount {
return _count;
}
- (bool**)allocateNewGrid:(NSInteger)row column:(NSInteger)column {
bool **p = malloc(row * sizeof(bool*));
for (int i = 0; i < row; ++i) {
p[i] = malloc(column * sizeof(bool));
}
return p;
}
- (void)generateNewGrid:(NSInteger)row column:(NSInteger)column {
[self freeGrid];
_grid = [self allocateNewGrid:row column:column];
_count = [self.algorithmDelegate generateGrid:_grid];
_score = _count * 100;
}
- (BOOL)isMarkedAtRow:(NSInteger)row column:(NSInteger)column {
return YES;
}
- (void)freeGrid {
for (int i = 0; i < _row; ++i) {
free(_grid[i]);
}
free(_grid);
}
- (void)dealloc {
[self freeGrid];
}
#end
It's perfectly normal to use a C array in an Obj-C class. There are no low level data types in Obj-C — every class, including NSArray, NSString, etc, is using primitive C types internally.
However you are doing a few things wrong:
Do not use #synthesize unless you need to. In this case you don't need it, so delete those lines of code.
Do not use _foo to access variables unless you need it, again in this case you don't need it in any of your use cases (except, arguably, in your init and dealloc methods. But I would argue it should not even be used there. Other people disagree with me). My rule is to only use _foo when I run into performance issues when using self.foo syntax. There are also edge case issues such as KVO where you might run into problems when using an accessor inside init/dealloc. In the real world I have never run into any of those edge cases in more than 10 years of writing Obj-C — I always use accessors, unless they're too slow.
Some implementation details about how to declare an #property of a C array: Objective-C. Property for C array
I have seen so many helpful threads here, but this is my first time posting!
I was working on the infamous Stanford OpenCourse project: Matchismo. While I got everything going just fine, but I don't understand one part of the sample codes.
Basically the code below is used to get a Card object to compare with another card.
- (void) flipCardAtIndex: (NSUInteger)index
{
Card *card = [self cardAtIndex:index];
if (card && !card.isUnplayable)
{
if (!card.isFaceUp)
{
for (Card* otherCard in self.cards)//for-in loop
{
if (otherCard.isFaceUp && !otherCard.isUnplayable)
{
int matchScore = [card match:#[otherCard]];
......
And this is how cardAtIndex works:
-(Card *) cardAtIndex:(NSUInteger)index
{
if (index < [self.cards count])
//dot notation is used for property
//[] is used for method
{
return self.cards[index];
}
return nil;
}
Here are the methods for Match(card*) and Match(playingCard)
Match(card*)
-(int) match:(NSArray *)otherCards
{
NSLog(#"here");
int score = 0;
for (Card *card in otherCards)
{
if ([card.content isEqualToString:self.content])
score = 1;
{
NSLog(#"Card Match");
}
}
return score;
}
Match(PlayingCard*)
-(int) match: (NSArray *)otherCards;
{
int score = 0;
if ([otherCards count] == 1)
{
PlayingCard *otherCard = [otherCards lastObject];//the last object in the array
if ([otherCard.suit isEqualToString:self.suit])
score = 1;
else if (otherCard.rank == self.rank)
score = 4;
NSLog(#"PlayingCard Match");
}
return score;
}
It worked just fine, but I don't get why when a Card* object calls a method, its subclass's PlayingCard's method is invoked.
Thanks so much for help me!
This concept is called Polymorphism.
It allows you to have a base class which provides some interface, and a set of subclasses that implement these methods in some different ways. The classic example is a Drawable class method draw, and its subclasses Circle and Rectangle, that both override the draw method to render themselves in some specific manner.
So goes for your Card base class, it calls its own interface method match, but as an object is actually not an instance of Card, but of a PlayingCard subclass, subclass method gets called instead to provide specific implementation.
In your view controller .m file, the property "deck" must be initialized as class PlayingCardDeck, and in PlayingCardDeck.m, the class of card is PalyingCard. So even though you declared your card as class Card, the method it calls will still be the one in class PlayingCard.
I'm new to Objective-C and C in general. I've been looking around and I couldn't find the solution to this issue. Any help would be appreciated.
I have the following global variables
CCSprite* BackgroundImage;
CCSprite* BackgroundGhost;
CCSprite* Globe;
CCSprite* Logo;
in my init I call a function and pass the global variables as parameters.
if(_ourDevice == iPad)
{
[self CustomCodeSetAssetForIpad:BackgroundImage ghost:BackgroundGhost TheGlobe:Globe AndTheLogo:Logo];
}
Here is the code for CustomCodeSetAssetForIpad:
-(void) CustomCodeSetAssetForIpad:(CCSprite*) _Background ghost:(CCSprite*) _BackgroundGhosts TheGlobe:(CCSprite*)_Globes AndTheLogo:(CCSprite*) _Logos
{
_Background = [CCSprite spriteWithFile:#"1028-768-sunray.png"];
_BackgroundGhosts = [CCSprite spriteWithFile:#"1028-768-sunray.png"];
_Globes = [CCSprite spriteWithFile:#"BigGlobe.png"];
_Logos = [CCSprite spriteWithFile:#"DefaultLogo.png"];
[_BackgroundGhosts setAnchorPoint:CGPointMake(0.5, 0)];
[_BackgroundGhosts setScale:2];
[_BackgroundGhosts setOpacity:120];
//[BackgroundGhost setPosition: CGPointMake(BackgroundGhost.position.x, BackgroundGhost.position.y-500)];
[_BackgroundGhosts setPosition:CGPointMake([[CCDirector sharedDirector]winSize].width/2, -100)];
[_Globes setAnchorPoint:CGPointMake(0.5, 0.5)];
[_Globes setScale:0.7];
[_Globes setPosition:CGPointMake([[CCDirector sharedDirector]winSize].width/2, -260)];
[_Logos setPosition:CGPointMake([self CenterOfTheScreen].x, [[CCDirector sharedDirector]winSize].height-[[CCDirector sharedDirector]winSize].height*0.2)];
[_Logos setScale:0.05];
}
The first few lines instantiate the global variables that were passed. However when the function is done, the reference to those objects are lost. I thought when you pass a pointer to a function, as the object is instantiated, it would retain its reference to the instantiated object. Am I missing something here?
Ah... Variables of type classname * are effectively references to instances of that class. So in your case, _Background is an instance reference passed in as an argument to your function. If you are trying to return multiple results from a function (via pointers), your arguments should really of type classname **, which is a pointer to a reference.
So the calling code would look like this:
CCSprite * background = nil ;
CCSprite * ghosts = nil ;
CCSprite * globes = nil ;
CCSprite * logos = nil ;
[ self customCodeSetAssetForIpad:&background ghosts:&ghosts globes:&globes logos:&logos ] ;
And your method looks like this:
-(void)customCodeSetAssetForIPad:(CCSprite**)background ghosts:(CCSprite**)backgroundhosts globe:globes logos:(CCSprite**)logos
{
*background = [CCSprite spriteWithFile:#"1028-768-sunray.png"];
// ... the rest of your code ...
}
Also, I took the liberty of making your method name and variable names more objective-c like (methods and variables begin with lowercase letters)
EDIT: I'd personally structure it like this:
//
// World... global things go in here
//
#interface World
#property ( nonatomic, readonly, strong ) CCSprite * background ;
+(id)theWorld // accessor to get the global world object
#end
#implementation World
#synthesize CCSprite * background = _background ;
static World * __theWorld = nil ; // global variable to hold our shared global World instance
+(void)load
{
// when this class is loaded, create our global world object
__theWorld = [ [ [ self class ] alloc ] init ] ;
}
+(id)theWorld
{
return __theWorld ;
}
// return the background sprite, creating it if it hasn't be created yet
-(CCSprite*)background
{
if ( !_background) { _background = [ CCSprite spriteWithFile:[CCSprite spriteWithFile:#"1028-768-sunray.png"] ; }
return _background ;
}
#end