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
Related
I'm fairly new to Objective-C; but have been coding for years and this one really stumps me.
I'm trying to build an iPhone app and wanted to create a "settings" screen which will use a Table format. (Xcode 5.1.1).
I want to future proof the main Settings screen and make it easy for the application coding by hiding the "hard work" in subroutines/methods.
I may be getting too clever but I've created a class for each 'setting' that contains screen prompts, default values etc and using an Enum to cross-reference it (so the compiler will highlight typos etc)
The problem I'm encountering is that when I add entries to my NSMutableDictionary and use lldb to print the values; every entry seems to have the same "key" and values. I've tried converting the eNum to an NSNumber and also as an NSString -- no difference in the result - so I'm obviously doing something else daft but just can't see it
The following code is from various .m & .h files, I've omitted boring stuff that you always "have to have" to keep it short
// basic x-ref I want to use in my code
typedef NS_OPTIONS(NSInteger, ConfigurationType) {
unDefined = -1,
Server = 0,
Id = 1,
Phone = 2
};
// definition for a "single" Settings value
#interface SettingDefinition : NSObject
#end
#implementation SettingDefinition
ConfigurationType _cfgType;
NSString *_cfgName;
NSString *_screenTitle;
NSString *_value;
- (NSString *)description
{
NSString *className = NSStringFromClass([self class]);
return [NSString stringWithFormat:#"<%#: x%p Type=%d dbKey=%# '%#' -> %#>", className, self, _cfgType, _cfgName, _screenTitle, _value];
}
- (id)initType:(ConfigurationType)cfgOption
withDbKey: (NSString*)dbKey
asOptionTitle:(NSString*)cfgTitle
withValue:(NSString*)itmValue
{
self = [super init];
if (self) {
_screenTitle = cfgTitle;
_cfgName = dbKey;
_cfgType = cfgOption;
_value = itmValue;
}
return self;
}
#end
#interface Configuration : NSObject
#end
#implementation Configuration {
NSMutableDictionary *Settings; // List of Setting structures
};
- (id)init {
self = [super init];
if (self) {
Settings = [[NSMutableDictionary alloc]init];
[self add:Server withDbKey:#"Server" asOptionTitle:#"Server"];
[self add:Id withDbKey:#"Id" asOptionTitle:#"Your ID"];
[self add:Phone withDbKey:#"Phone" asOptionTitle:#"Phone No."];
}
return self;
}
- (void) add:(ConfigurationType)cfgOption
withDbKey:(NSString*)dbKey
asOptionTitle:(NSString*)cfgTitle
{
NSString * itmValue = [self configurationValue: cfgOption cfgName:dbKey];
SettingDefinition *x = [[SettingDefinition alloc]
initType: cfgOption
withDbKey: dbKey
asOptionTitle: cfgTitle
withValue: itmValue];
[Settings setObject:x forKey:[self asKey:cfgOption]];
}
- (NSString *) asKey:(ConfigurationType) settingType {
NSString *rc = [NSString stringWithFormat:#"%d", settingType];
return rc;
}
- (NSString *) configurationValue:(ConfigurationType) settingType {
// returns a suitable value from my system setup
// which is initially a null value until the user sets everything up
}
the debug window shows the following when I break after the final call to [self add: ...]
(lldb) po Settings
{
0 = "<SettingDefinition: x0x8e7c280 Type=2 dbKey=Phone 'Phone No.' -> (null)>";
1 = "<SettingDefinition: x0x8c703a0 Type=2 dbKey=Phone 'Phone No.' -> (null)>";
2 = "<SettingDefinition: x0x8e7c310 Type=2 dbKey=Phone 'Phone No.' -> (null)>";
}
The (null) is obviously due to no data in 'value' yet; but why do they all show as 'Phone'; if I break after the second call to [self add:..] they all show as 'Id'
UPDATE:
DOH! obviously they're globals (I've been using another IDE where everything is local until exposed) .. If I enclose them in braces in the implementation as the documentation states then the exhibited problem vanishes. I have properties to access the variables but as the setter does more than just set the memory, I thought I'd need my "own" variables to hold the data.. said it was something daft .. thank you!
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.
I have a problem with assigning values to a string and then getting them back. The string is a property of a class, because I need it to carry over to other view controllers. (I have tried Core Data, but it didn't work either and this seemed simpler.)
The class for the strings is this:
.h
#interface GameInformation : NSObject
#property (nonatomic, retain) NSString *word;
#property (nonatomic, retain) NSString *mode;
#end
.m
#implementation GameInformation
#synthesize mode = _mode;
#synthesize word = _word;
#end
Pretty simple. The relevant code in app delegate:
GameInformation *gameInfo = [GameInformation alloc].init;
optionsView.gameInfo = gameInfo;
oneBox.gameInfo = gameInfo;
twoBox.gameInfo = gameInfo;
And so on, until I've got all the controllers covered. Options view is where I set the value for the strings, and test those values.
GameInformation *info = [self gameInfo];
UISegmentedControl *selectMode = [self mode];
UISegmentedControl *gameWord = [self word];
if (selectMode.selectedSegmentIndex == 0)
{
info.mode = #"regular";
} else if (selectMode.selectedSegmentIndex == 1) {
info.mode = #"wordTap";
}
if (gameWord.selectedSegmentIndex == 0)
{
info.word = #"regular";
} else if (gameWord.selectedSegmentIndex == 1) {
info.word = #"hat";
} else if (gameWord.selectedSegmentIndex == 2) {
info.word = #"dog";
} else if (gameWord.selectedSegmentIndex == 3) {
info.word = #"book";
} else if (gameWord.selectedSegmentIndex == 4) {
info.word = #"bus";
} else if (gameWord.selectedSegmentIndex == 5) {
info.word = #"cup";
} else if (gameWord.selectedSegmentIndex == 6) {
info.word = #"pig";
}
NSLog(#"%#", info.mode);
NSLog(#"%#", info.word);
And the log comes out as null when those are passed over. I have tried [info setWord:#"regular"]; and [info setMode#"regular"]; but those didn't work either.
I haven't tried using the strings in the one box, two box, etc. controllers yet, because the test return null.
So. What am I doing wrong? Or am I barking up the wrong tree? And, like I said earlier, trying to use core data for this didn't work and this seemed like a simpler approach.
Thanks in advance!
EDIT:
Thank you all for the quick comments! I did a NSLog on info and it is indeed null. I also changed the declarations to copy instead of retain, and changed the dot notation in the alloc statement. The alloc statement is in the app delegate's didFinsihLaunchingWithOptions. Is that the wrong place?
Thanks again for the help!
I have searched and can't find the assert to this. I know it must be a fundamental thing I'm missing here.
I have an enum:
typedef enum {
NINETYBEND, NINETYBEND_FAST, NINETYBEND_SLOW, STRAIGHT
} BlockTypeEnum;
I am trying to use these values in objects I am creating like this:
BlockTypeEnum blockType = STRAIGHT;
XMLLevelPiece* piece = [[XMLLevelPiece alloc] init];
[piece initPiece:blockType];
My problem occurs when I try to use the same variable twice. If I create one object with an enum, change the enum and then create a second object using it, the enum in my first object changes to the second enum value. This is not what I want. Example below:
BlockTypeEnum blockType = STRAIGHT;
XMLLevelPiece* piece = [[XMLLevelPiece alloc] init];
[piece initPiece:blockType];
blockType = NINETYBEND_FAST;
XMLLevelPiece* piece2 = [[XMLLevelPiece alloc] init];
[piece2 initPiece:blockType];
NSLog([NSString stringWithFormat:#"%d", [piece getBlockType]]);
NSLog([NSString stringWithFormat:#"%d", [piece2 getBlockType]]);
//BOTH BLOCK TYPES ARE NOW NINETYBEND_FAST, NOT WHAT I WANTED!!
As far as I understood, an enum is just a glorified int, not a pointer, and I am reassigning the variable after adding to the first object. Please can someone tell me what I'm missing! Thanks very much, Simon.
Here is my code for XMLPiece, thanks!
#import "XMLLevelPiece.h"
#import "BlockType.h"
#import "GridCord.h"
#import "BlockColor.h"
#implementation XMLLevelPiece
BlockTypeEnum mBlockType;
BlockColorEnum mBlockColor;
int mRotation;
GridCord* mGridCords;
BlockColorEnum mLeftColor;
BlockColorEnum mTopColor;
BlockColorEnum mRightColor;
Boolean mRotatable;
Boolean mMoveable;
int mGroupID;
-(id) init
{
if( (self=[super init])) {
}
return self;
}
-(void)initPiece:(BlockTypeEnum)pBlockType pBlockColor:(BlockColorEnum)pBlockColor pRotation:(int)pRotation pGridCords:(GridCord*)pGridCords pLeftColor:(BlockColorEnum) pLeftColor pTopColor:(BlockColorEnum) pTopColor pRightColor:(BlockColorEnum) pRightColor pRotatable:(Boolean) pRotatable pMoveable:(Boolean) pMoveable pGroupID:(int) pGroupID
{
mBlockType = pBlockType;
mBlockColor = pBlockColor;
mRotation = pRotation;
mGridCords = pGridCords;
mLeftColor = pLeftColor;
mTopColor = pTopColor;
mRightColor = pRightColor;
mRotatable = pRotatable;
mMoveable = pMoveable;
mGroupID = pGroupID;
}
-(void)initPiece2
{
NSLog(#"poo");
}
-(Boolean)getRotatable
{
return mRotatable;
}
-(Boolean)getMoveable
{
return mMoveable;
}
-(int) getGroupID
{
return mGroupID;
}
-(BlockColorEnum) getLeftColor
{
return mLeftColor;
}
-(BlockColorEnum) getTopColor
{
return mTopColor;
}
-(BlockColorEnum) getRightColor
{
return mRightColor;
}
-(BlockTypeEnum) getBlockType
{
return mBlockType;
}
-(BlockColorEnum) getBlockColor
{
return mBlockColor;
}
-(int) getRotation
{
return mRotation;
}
-(id) getGridCords
{
return mGridCords;
}
-(void) setRotatable:(Boolean) pRotatable
{
mRotatable = pRotatable;
}
-(void) setMoveable:(Boolean) pMoveable
{
mMoveable = pMoveable;
}
#end
TL;DR
The answer is - that is not how you define ivars in Objective-C. I'm not even sure how that is supposed to behave but I can reproduce the error if I code it the same as you have.
I'd be interested for someone with more knowledge to explain what the behaviour/scope of those variable should be when they are defined like you have.
There's a lot of flaws in that code
You have not actually shown an initPiece:.
The long init... with all the arguments is likely a bad idea. Generally only add things to an init as either a convenience or if the object simply cannot function without it.
The use of get is not really correct in Objective-C
The class should potentially be defined more like
XMLLevelPiece.h
// You will need to import the header with the BlockTypeEnum defined
#interface XMLLevelPiece : NSObject
#property (nonatomic, assign) BlockTypeEnum blockType;
// .. Other properties
- (id)initWithPiece:(BlockTypeEnum)blockType; // I'm not so sure you need this
#end
XMLLevelPiece.m
#import "XMLLevelPiece.h"
#import "BlockType.h"
#import "GridCord.h"
#import "BlockColor.h"
#implementation XMLLevelPiece
#synthesize blockType = mBlockType;
- (id)initWithPiece:(BlockTypeEnum)blockType;
{
self = [super init];
if (self) {
mBlockType = blockType;
}
return self;
}
#end
Then you can use it like
BlockTypeEnum blockType = STRAIGHT;
XMLLevelPiece *p1 = [[XMLLevelPiece alloc] initWithPiece:blockType];
blockType = NINETYBEND_FAST;
XMLLevelPiece *p2 = [[XMLLevelPiece alloc] initWithPiece:blockType];
NSLog(#"%d", p1.blockType);
NSLog(#"%d", p2.blockType);
Which for me results in:
2012-01-08 15:29:31.782 Untitled[1297:707] 3
2012-01-08 15:29:31.791 Untitled[1297:707] 1
Optional observations
If you can do away with the dedicated initializer, the usage would look more like:
BlockTypeEnum blockType = STRAIGHT;
XMLLevelPiece *p1 = [[XMLLevelPiece alloc] init];
p1.blockType = blockType;
// all other assignments
blockType = NINETYBEND_FAST;
XMLLevelPiece *p2 = [[XMLLevelPiece alloc] init];
p2.blockType = blockType;
// all other assignments
NSLog(#"%d", p1.blockType);
NSLog(#"%d", p2.blockType);
To remove a couple of superflous lines you could remove the local blockType variable and assign the value straight to the object:
XMLLevelPiece *p1 = [[XMLLevelPiece alloc] init];
p1.blockType = STRAIGHT;
Your method call to initWithPiece does not match the definition.
Call:
[piece initPiece:blockType];
Definition:
-(void)initPiece:(BlockTypeEnum)pBlockType pBlockColor:(BlockColorEnum)pBlockColor pRotation:(int)pRotation pGridCords:(GridCord*)pGridCords pLeftColor:(BlockColorEnum) pLeftColor pTopColor:(BlockColorEnum) pTopColor pRightColor:(BlockColorEnum) pRightColor pRotatable:(Boolean) pRotatable pMoveable:(Boolean) pMoveable pGroupID:(int) pGroupID
Comments:
In general method calls with more than a few parameters are best a poor idea. Probably better in this case is using individual setters.
The convention in Objective-C as per Apple is to name getters without the "get" prefix. In fact a get prefix signifies a value returned via a reference parameter, not as the return result. Such usage will confuse the Analyzer and cause problems if using ARC.
I ran into this issue twice now, and am curious to know if there is a correct way of getting the following example to work. I know there are other ways /workarounds for doing the same thing but I am wondering why the compiler doesn't recognise my casting and if I am missing something obvious here.
Suppose I have two table views with different style header views that I need to provide. SectionHeaderViewA is a UIView subclass with a custom property textLabelA, SectionHeaderViewB is also a UIView subclass with a custom property textLabelB.
In the method:
- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
id headerView;
if (tableView.tag == TAG_A)
{
headerView = (SectionHeaderViewA*)[[SectionHeaderViewA alloc] init];
headerView.textLabelA = ... // I am unable to access the custom property here even after casting (SectionHeaderViewA*) above.
} else if (tableView.tag == TAG_B) {
headerView = (SectionHeaderViewB*)[[SectionHeaderViewB alloc] init];
headerView.textLabelB = ... // Same as above, even after casting the custom property is not recognised
}
return headerView;
}
Even after casting (SectionHeaderViewA*) and (SectionHeaderViewB*) to my headerView ivar, I am still unable to access their respective custom properties. It's like the compiler is still seeing headerView as an unknown / id type but why?
The cast is not in the correct place. Cast headerView before sending the appropriate textLabel A or B message.
id headerView;
if (tableView.tag == TAG_A)
{
headerView = [[SectionHeaderViewA alloc] init];
((SectionHeaderViewA*)headerView).textLabelA = ... // I am unable to access the custom property here even after casting (SectionHeaderViewA*) above.
} else if (tableView.tag == TAG_B) {
headerView = [[SectionHeaderViewB alloc] init];
((SectionHeaderViewB*)headerView).textLabelB = ... // Same as above, even after casting the custom property is not recognized
}
return headerView;
Once you move the cast, you will be able to send the correct message.
the type of headerView is "id", which means it doesn't know about your extra properties etc (the cast doesn't change the type of "headerView").
you could do something like:
if (tableView.tag == TAG_A)
{
SectionHeaderViewA* headerView = [[SectionHeaderViewA alloc] init];
headerView.textLabelA = ...
return headerView;
} else if (tableView.tag == TAG_B) {
SectionHeaderViewB* headerView = [[SectionHeaderViewB alloc] init];
headerView.textLabelB = ...
return headerView;
}
return nil;
Your cast is not doing anything as you are casting into id.
Whilst #sean's answer works and it does the single exit it is pretty ugly having all the curly brackets I would probably go for
id headerView = nil; // Initialize to nil... you may not go into either side of your if
if (TAG_A == tableView.tag) {
SectionHeaderViewA *sectionHeaderViewA = [[SectionHeaderViewA alloc] init];
sectionHeaderViewA.textLabelA = ...
headerView = sectionHeaderViewA;
} else if (TAG_B == tableView.tag) {
SectionHeaderViewB *sectionHeaderViewB = [[SectionHeaderViewB alloc] init];
sectionHeaderViewB.textLabelB = ...
headerView = sectionHeaderViewB;
}
return headerView;
Or another possibility (potentially over engineering the problem) is make both sectionHeaderViewA and sectionHeaderViewB conform to a protocol and then you can make it a little tidier still.
SectionHeaderInterface.h
#protocol SectionHeaderInterface <NSObject>
#property (strong, nonatomic) UILabel *textLabel;
#end
SectionHeaderView(A|B).h
#import "SectionHeaderInterface.h"
#interface SectionHeaderView(A|B) : UIView <SectionHeaderInterface>
// ... rest of interface
#end
SectionHeaderView(A|B).m
#implementation SectionHeaderView(A|B)
#synthesize textLabel = _textLabel;
// ... rest of your class
#end
YourController.m
id<SectionHeaderInterface> headerView = nil; // Initialize to nil... you may not go into either side of your if
if (TAG_A == tableView.tag) {
headerView = [[SectionHeaderViewA alloc] init];
} else if (TAG_B == tableView.tag) {
headerView = [[SectionHeaderViewB alloc] init];
}
headerView.textLabel.text = ...
return headerView;