Objective C enumeration type in object changing on reassignment - objective-c

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.

Related

How to parse and take only this string value

I wanted to get only array string value app. As example(SLGoogleAuth ,HalfTunes,TheBackgrounder,Calculiator) . But don't know how to do?
It's a code.
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//
Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");
SEL selector=NSSelectorFromString(#"defaultWorkspace");
NSObject* workspace = [LSApplicationWorkspace_class performSelector:selector];
SEL selectorALL = NSSelectorFromString(#"allApplications");
NSLog(#"apps: %#", [workspace performSelector:selectorALL]);
}
It's output:
Thanks in advance
You do not want to parse that. NSLog prints out a description of an object. You want to access that value directly.
[LSApplicationWorkspace allApplications];
returns NSArray of LSApplicationProxy. LSApplicationProxy class has a ivar _bundleURL that contains information that you need. You need runtime functions to access it. Working example below:
// #import <objc/runtime.h>
Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");
SEL selector=NSSelectorFromString(#"defaultWorkspace");
NSObject* workspace = [LSApplicationWorkspace_class performSelector:selector];
SEL selectorALL = NSSelectorFromString(#"allApplications");
NSArray* appProxies = [workspace performSelector:selectorALL];
Ivar bundleUrlIvar = class_getInstanceVariable([appProxies.firstObject class], "_bundleURL");
NSMutableString* result = [NSMutableString string];
for (id appProxy in appProxies)
{
NSURL* url = object_getIvar(appProxy, bundleUrlIvar);
// at this point you have the information and you can do whatever you want with it
// I will make it a list as you asked
if (url)
{
[result appendFormat:#",%#", [url lastPathComponent]];
}
}
if (result.length > 0)
{
// remove comma from beginning of the list
[result deleteCharactersInRange:NSMakeRange(0, 1)];
}
NSLog(#"apps: %#", result);
Note that this will be rejected by AppStore as you are using private apis. So use at your own discretion.

Accessing Property from another NSObjectClass

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

NSMutableDictionary - entries appear to be over-written by each addition

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!

Array object doesn't retain it's data

I have an object that contains a array. On initialization of this object, the array is allocated and properly filled (as I can see in the debugger). This object is use to manage elements in a single view.
My problem is that when I try to call the object a second time, the array (and all other parameter of this object) are nil yet they have a memory address (again as seen in debugger).
This is the .h of the object in question :
#import <Foundation/Foundation.h>
#import "ObjectDef.h"
#import "AbstractNode.h"
#interface RenderingMachine : NSObject
{
NSMutableArray* _objectID; // pair list
NSMutableArray* _objectList; // node list
ObjectDef* _defs; // definition of pairs
unsigned int _size;
unsigned int _edgeSize;
AbstractNode* _lastNode;
}
-(void) InitializeMachine;
-(bool) AddObjectByIndex:(int)index :(float)x :(float)y :(float)originX :(float)originY;
-(bool) AddObjectByType:(NSString*)type;
-(NSMutableArray*) GetObjectID;
-(NSMutableArray*) GetObjectList;
-(unsigned int) Size;
-(void) DrawAllNode;
-(int) ComputePar;
-(void) ComputeLastEdge:(int)edgeCount;
//+(RenderingMachine*) GetMachine;
#end
My main problem right now is with _defs which is filled in InitDefinitions :
-(void) InitializeMachine
{
_defs = [[ObjectDef alloc] init];
[_defs InitDefinitions];
_objectID = [[NSMutableArray alloc] init];
_objectList = [[NSMutableArray alloc] init];
_objectID = [NSMutableArray arrayWithObject:[_defs GetPair:3]]; // adding the field node ID
AbstractNode* rootNode = [[FieldNode alloc] init];
_objectList = [NSMutableArray arrayWithObject:rootNode]; // adding the field node as root node
_size = 1;
_edgeSize = 0;
}
What I'd like to know is if might be a bad alloc / init call or could it be a problem with the ARC of xcode because this particular file compiles with ARC (the other being ignore with "-fno-objc-arc").
Also, as mentionned the _defs is problematic, but all the property declared under #interface are having the same problem.
First you create a retained object with _objectID = [[NSMutableArray alloc] init];
and then you overwrite it with an autoreleased one _objectID = [NSMutableArray arrayWithObject:[_defs GetPair:3]];
to add the object better use [_objectID addObject:[_defs GetPair:3]];
same thing with the _objectList Object

Custom classes & casting inside conditional statements in Objective-C

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;