Method to instantiate objects - objective-c

Would like to create a method that instantiate objects. 
- (NSArray *) make3Of : (Class) type
{
...
type * temp = [[type alloc] ...
...
}
But I get a warning from Xcode ...
Actual warning:
"Class method +alloc not found (return type defaults to 'id')"
Is there a better/correct way to do this?
Actual code:
- (NSArray *) getBoxesOfType: (Class <ConcreteBox>) type StartingFrom: (uint64_t) offset
{
NSMutableArray *valueArray = [[NSMutableArray alloc]initWithObjects: nil];
for (uint64_t i = offset; i< boxStartFileOffset + self.size; i += [self read_U32_AtBoxOffset:i])
{
if ([[self read_String_OfLen:4 AtBoxOffset:offset + 4] isEqual:[type typecode]]) {
[[type alloc]initWithFile:file withStartOffset:i]; //warning here;
//yes I plan to assign it to a variable
//(originally of "type" but that won't work as AliSoftware pointed out, will be using "id" instead.
...
}
}
}
Same as example, I'm trying to instantiate a couple of objects.
Code for protocol:
#import <Foundation/Foundation.h>
#protocol ConcreteBox
+ (NSString *) typecode;
- (id) initWithFile: (NSFileHandle *) aFile withStartOffset: (uint64_t) theOffset;
#end

You can't use a variable (in your case type)... as a type for another variable!
In your code, both type and temp are variables, that's a syntax error.
As you don't know the type of the variable as compile time, use the dynamic type id instead. This type is specifically designed to handle cases when the type is not defined at compile time.
So your code will look like this:
-(NSArray*)make3Of:(Class)type {
id obj1 = [[[type alloc] init] autorelease];
id obj2 = [[[type alloc] init] autorelease];
id obj3 = [[[type alloc] init] autorelease];
return [NSArray arrayWithObjects:obj1, obj2, obj3, nil];
}

Related

How to add new array element from another method in Objective-c?

I have some array( #private NSArray employees []; ) and method , which take string parameter( name of employees) and put this parameter in array. How I can do this with Objective-c?
You could do the following,
Create a property,
#property (nonatomic) NSMutableArray *array;
Initialise the array in your init method or somewhere else appropriate,
self.array = [[NSMutableArray alloc] init];
Your method could look something like this,
- (void)addEmployeeName:(NSString *)employeeName {
[self.array addObject:employeeName];
}
You can create a class Employee and use a type with your array.
For example:
NSArray<Employee*> * employees = [[NSArray alloc] init];
At this point, your method will be:
-(Employee *)createEmployee:(NSString *)name{
Employee *myEmpl = [[Employee alloc]init];
[myEmpl setName:name];
return myEmpl;
}
and you can add the object (of type Employee) in your array in this way:
[employees addObject:[self createEmployee]];
the same thing is possibile with an object of type NSString instead of Employee.
You can also avoid defining the type in your NSArray because Objective-C use the type inference

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!

Create a NSSet from NSArray based on property

How does one create a NSSet of objects from an array based on a property.
e.g. Array of objects, each with a strong reference to a type property, and multiple occurrences of each type exist in the array. How can this be turned into an NSSet holding a single object of each type.
NSSet *distinctSet = [NSSet setWithArray:[array valueForKeyPath:#"#distinctUnionOfObjects.property"]];
A dictionary essentially has this functionality already. Its keys are a set, so you can create the dictionary to hold the objects, keyed by whatever attribute you're interested in:
[NSDictionary dictionaryWithObjects:arrayOfObjects
forKeys:[arrayOfObjects valueForKey:theAttribute]];
If you ask the dictionary for allValues now, you have only one object for each attribute. I should mention that with this procedure, the later objects will be kept in favor of earlier. If the order of your original array is significant, reverse it before creating the dictionary.
You can't actually put those objects into an NSSet, because the NSSet will use the objects' isEqual: and hash methods to determine whether they should be members, rather than the key attribute (of course, you can override these methods if this is your own class, but that would likely interfere with their behavior in other collections).
If you really really feel that you need a set, you will have to write your own class. You can subclass NSSet, but conventional wisdom is that composition of Cocoa collections is far easier than subclassing. Essentially, you write a class which covers any set methods you're interested in. Here's a (quite incomplete and totally untested) sketch:
#interface KeyedMutableSet : NSObject
/* This selector is performed on any object which is added to the set.
* If the result already exists, then the object is not added.
*/
#property (assign, nonatomic) SEL keySEL;
- (id)initWithKeySEL:(SEL)keySEL;
- (id)initWithArray:(NSArray *)initArray usingKeySEL:(SEL)keySEL;
- (void)addObject:(id)obj;
- (NSArray *)allObjects;
- (NSArray *)allKeys;
- (BOOL)containsObject:(id)obj;
- (NSUInteger)count;
-(void)enumerateObjectsUsingBlock:(void (^)(id, BOOL *))block;
// And so on...
#end
#import "KeyedMutableSet.h"
#implementation KeyedMutableSet
{
NSMutableArray * _objects;
NSMutableSet * _keys;
}
- (id)initWithKeySEL:(SEL)keySEL
{
return [self initWithArray:nil usingKeySEL:keySEL];
}
- (id)initWithArray:(NSArray *)initArray usingKeySEL:(SEL)keySEL
{
self = [super init];
if( !self ) return nil;
_keySEL = keySEL;
_objects = [NSMutableArray array];
_keys = [NSMutableSet set];
for( id obj in initArray ){
[self addObject:obj];
}
return self;
}
- (void)addObject:(id)obj
{
id objKey = [obj performSelector:[self keySEL]];
if( ![keys containsObject:objKey] ){
[_keys addObject:objKey];
[_objects addObject:obj];
}
}
- (NSArray *)allObjects
{
return _objects;
}
- (NSArray *)allKeys
{
return [_keys allObjects];
}
- (BOOL)containsObject:(id)obj
{
return [_keys containsObject:[obj performSelector:[self keySEL]]];
}
- (NSUInteger)count
{
return [_objects count];
}
- (NSString *)description
{
return [_objects description];
}
-(void)enumerateObjectsUsingBlock:(void (^)(id, BOOL *))block
{
for( id obj in _objects ){
BOOL stop = NO;
block(obj, &stop);
if( stop ) break;
}
}
#end
NSMutableSet* classes = [[NSMutableSet alloc] init];
NSMutableSet* actualSet = [[NSMutableSet alloc] init];
for(id object in array) {
if([classes containsObject:[object class]] == NO) {
[classes addObject:[object class]];
[actualSet addObject:object];
}
}
You would use:
NSSet* mySetWithUniqueItems= [NSSet setWithArray: yourArray];
This should work regardless of the type of objects in your array and would populate the NSSet with only one occurence of any duplicate objects in your array.
I hope this helps.
Update:
Next best thing: is use concatenation of class name and object property first then use the above method.
self.concatenatedArray=[NSMutableArray arrayWithCapacity:4];
for (TheClass* object in self.myArray)
[self.concatenatedArray addObject:[NSString stringWithFormat:#"%#-%#",[object class], object.theProperty]];
self.mySet=[NSSet setWithArray:self.concatenatedArray];
I am not sure what you will use the NSSet output for but you can probably modify the concatenation elements to have the information you need in the NSSet output.
I have created a simple library, called Linq to ObjectiveC, which is a collection of methods that makes this kind of problem much easier to solve. In your case you need the Linq-to-ObjectiveC distinct method:
NSSet* dictionary = [NSSet setWithArray:[sourceArray distinct:^id(id item) {
return [item type] ;
}]];
This returns a set where each item has a distinct type property.

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

Question about isKindOfClass

Please look at this code snipped
- (SoapRequest*)AddFlyData:(id)_target
action:(SEL)_action
sessionid:(int)sessionid
datasets:(FlyNetArrayOfDataSet*)datasets
{
if ([datasets isKindOfClass:[FlyNetArrayOfDataSet class]]) {
NSLog(#"Yeah");
} else {
NSLog(#"Not Yeah");
}
}
Why, when i look on my console, I get
2011-09-06 23:08:00.917 soap-test[2133:207] Not Yeah
I'm a beginner and I'm completely confused .. :s When I look in the Debugger, the variable type is SoapArray (who is the parent class of FlyNetArrayOfDataSet).
I used a method from SoapArray to initiate my instance of 'datasets', that means the class is automatically defined as Soap and not as FlyNetArrayOfDataSet ?!
Thank you
EDIT: I made a mistake, it's not NSArray but it inherits from SoapArray
This is the header file of the class FlyNetArrayOfDataSet
#import "Soap.h"
#interface FlyNetArrayOfDataSet : SoapArray
{
}
+ (NSMutableString*) serialize: (NSArray*) array;
#end
But that didn't explain me why isKindOfClass returns false ..
EDIT2: Ok I have the response of my question..
I used this method to initialize my instance
FlyNetArrayOfDataSet * arr = [FlyNetArrayOfDataSet arrayWithObject:data];
This is a static method of the superclass SoapArray that create an instance of SoapArray (Helper) .. but not an instance of FlyNetArrayOfDataSet (!)
Look at its implementation :
+ (id)arrayWithObjects:(id)firstObj, ...{
SoapArray* a = [SoapArray array];
id eachObject;
va_list argumentList;
if (firstObj) {
[a.items addObject: firstObj];
va_start(argumentList, firstObj);
while (eachObject = va_arg(argumentList, id)) {
[a.items addObject: eachObject];
}
va_end(argumentList);
}
return a;
}
If I initialize my instance like this
FlyNetArrayOfDataSet * arr = [[FlyNetArrayOfDataSet alloc] init];
It's work perfectly and the method isKindOfClass return true :-)
Suppose you have a class named "FlyNetArrayOfDataSet" which inherits from (=is a subclass of) NSArray.
If you instantiate a variable like:
FlyNetArrayOfDataSet *arr = [[FlyNetArrayOfDataSet alloc] init];
As you can see, I'm initializing the array with a method of NSArray. However, my "arr" object will be of kind FlyNetArrayOfDataSet, and NOT NSArray, because I called the FlyNetArrayOfDataSet class (see [FlyNetArrayOfDataSet arrayWithObject....).
NSLog(#"%d", [arr isKindOfClass:[FlyNetArrayOfDataSet class]]);
NSLog(#"%d", [arr isKindOfClass:[NSArray class]]);
Both will return "1", which means "true", because arr is an object of the FlyNetArrayOfDataSet class, which inherits from NSArray.
EDIT
Let's see if I can explain it better:
arr1 = [[FlyNetArrayOfDataSet alloc] init];
arr2 = [[NSArray alloc] init];
Both objects, arr1 and arr2, are created with the same method, which is defined in the class NSArray. However, in the first case the class which is being called is FlyNetArrayOfDataSet and in the second case is NSArray. Thus, arr1 will be an object of class FlyNetArrayOfDataSet, while arr2 will be of class NSArray.
The difference can be seen in this code:
NSLog(#"%d %d",
[arr1 isKindOfClass:[FlyNetArrayOfDataSet class]]
[arr1 isKindOfClass:[NSArray class]]
);
NSLog(#"%d %d",
[arr2 isKindOfClass:[FlyNetArrayOfDataSet class]]
[arr2 isKindOfClass:[NSArray class]]
);
The output of this code is:
1 1 ( = true true)
0 1 ( = false true)
that's because FlyNetArrayOfDataSet is a SoapArray and SoapArray is not a FlyNetArrayOfDataSet.
if datasets were an instance of SoapArray, you will see "Soap" in the following example:
- (SoapRequest*)addFlyData:(id)target
action:(SEL)action
sessionid:(int)sessionid
datasets:(FlyNetArrayOfDataSet*)datasets
{
if ([datasets isKindOfClass:[FlyNetArrayOfDataSet class]]) {
NSLog(#"Fly");
}
else if ([datasets isKindOfClass:[SoapArray class]]) {
NSLog(#"Soap");
}
else {
NSLog(#"???");
}
}
it's possible that an instance of SoapArray is also FlyNetArrayOfDataSet. the other possibilities are:
a SoapArray
subclass other than FlyNetArrayOfDataSet.