How can I create a class with the initializer initWithObjects?
Or does it just make more sense to inherit from NSArray and work around it that way?
initWithObjects: is implemented using a C variable argument list. Here's an example implementation:
- (void)setContentByAppendingStrings:(NSString *)firstArg, ...
{
NSMutableString *newContentString = [NSMutableString string];
va_list args;
va_start(args, firstArg);
for (NSString *arg = firstArg; arg != nil; arg = va_arg(args, NSString*))
{
[newContentString appendString:arg];
}
va_end(args);
[contents autorelease];
contents = [newContentString retain];
}
See this page for more info.
#interface foo : NSObject {
NSArray* objects;
}
-(id)initWithObjects:(NSArray*)array;
#end
#implementation foo
-(id)initWithObjects:(NSArray*)array{
if(self = [super init]){
objects = array;
}
return self;
}
#end
Related
I can't reference this in any way and get the void to run.
I can run the void in any other class just making a function and calling it but in this class there's no view did load. So the Q is, how do I run it?
I've tried referencing the variables from the other class but it gives compiler errors.
The return values from getCoords must be in the type double because it's coordinates.
#import "OmarAnnotation.h"
#import <CommonCrypto/CommonHMAC.h>
#import <netdb.h>
#import "AppDelegate.h"
#import "MapViewController.h"
#implementation SFAnnotation
#synthesize image;
#synthesize latitude;
#synthesize longitude;
#synthesize string;
+(void) getCoords {
NSString *string = #"http://jerwuqu.info/iambored/?GETPOS";
NSURL *url = [NSURL URLWithString:string];
NSString *otherURLContents = [NSString stringWithContentsOfURL:url];
NSLog(otherURLContents);
NSArray* foo = [otherURLContents componentsSeparatedByString: #","];
NSString *longi = [foo objectAtIndex: 0];
NSString *lati = [foo objectAtIndex: 1];
NSLog(longi);
NSLog(lati);
double latiDouble = [lati doubleValue];
double longiDouble = [longi doubleValue];
}
- (CLLocationCoordinate2D)coordinate;
{
double extern *latiDouble;
double extern *longiDouble;
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = latiDouble;
theCoordinate.longitude = longiDouble;
return theCoordinate;
}
- (void)dealloc
{
[image release];
[super dealloc];
}
- (NSString *)title
{
return #"Omar";
}
// optional
- (NSString *)subtitle
{
return #"Ortdenhegen";
}
#end
//This is my viewDidLoad in the other class file
- (void)viewDidLoad
{
self.mapView.mapType = MKMapTypeStandard; //Satelite?
self.mapAnnotations = [[NSMutableArray alloc] initWithCapacity:2];
SFAnnotation *sfAnnotation = [[SFAnnotation alloc] init];
[self.mapAnnotations insertObject:sfAnnotation atIndex:0];
[SFAnnotation getCoords]; // <- The line with an error
[self cityAction:self];
[self gotoLocation];
}
In the other class you're calling from, write [sfAnnotation whateverMethodYouWantToCall];
In example if you want to call getCoords from the other class's viewDidLoad:
-(void)viewDidLoad{
//Whatever code you have before.
[sfAnnotation getCoords];
//Whatever code you have after.
}
I know this can be done with many languages, but I don't see how to do it using Objective-C. I've read about singletons but as they are designed to be instanciated only once, they do not feed this need.
So this class could be called like this :
MyClass* obj1 = [[MyClass alloc] initWithKey:#"oneKey"];
NSString* lib = obj1.lib;
or
int id = [MyClass idForKey:#"anotherKey"];
I've tried this code but I'm pretty sure it's really bad, but I don't see how to achieve this :
.h file
#interface MyClass : NSObject {
NSString* key;
}
#property(nonatomic, retain) NSString* key;
#property(nonatomic, readonly) int id;
#property(nonatomic, readonly) NSString* lib;
#property(nonatomic, readonly) int value;
+ (id) classWithKey:(NSString*)theKey;
#end
.m file
#import "MyClass.h"
#interface MyClass.h (Private)
-(id)initWithKey:(NSString*)theKey;
#end
#implementation MyClass
#synthesize key;
static NSMutableDictionary* vars = nil;
-(id)init
{
if (!(self = [super init])) return nil;
self.key = nil;
[MyClass initVars];
return self;
}
-(id)initWithKey:(NSString*)theKey
{
if (!(self = [super init])) return nil;
self.key = theKey;
[MyClass initVars];
return self;
}
+ (id) classWithKey:(NSString*) theKey
{
return [[[MyClass alloc] initWithKey:theKey] autorelease];
}
+(void)initVars
{
if (vars != nil) return;
#define mNum(x) [NSNumber numberWithInt:x]
#define k0 #"id"
#define k1 #"lib"
#define k2 #"val"
vars = [NSMutableDictionary dictionary];
[vars setObject:[NSDictionary dictionaryWithObjectsAndKeys:mNum(5), k0, #"One value", k1, mNum(0), k2, nil] forKey:#"oneKey"];
[vars setObject:[NSDictionary dictionaryWithObjectsAndKeys:mNum(8), k0, #"Another value", k1, mNum(1), k2, nil] forKey:#"anotherKey"];
...
[vars retain];
}
- (int)id { return [[[vars objectForKey:self.key] objectForKey:k0] intValue]; }
- (NSString*)lib { return [[vars objectForKey:self.key] objectForKey:k1]; }
- (int)value { return [[[vars objectForKey:self.key] objectForKey:k2] intValue]; }
-(void)dealloc
{
self.key = nil;
[vars release];
[super dealloc];
}
+(int) idForKey:(NSString*)theKey
{
if (vars == nil) [self initVars];
return [[[vars objectForKey: theKey] objectForKey:k0] intValue];
}
#end
take a look at singleton class concept
there are a lot of answer for singletons, just search
here's' one:
Is this really a singleton?
I hope to add objects to a NSMutableArray "myArray", The NSMutableArray is the array for FileObj which has a NSString property "fileName"
#import <UIKit/UIKit.h>
#interface FileObj : NSObject {
NSString *fileName;
}
-(void) setfileName:(NSString *)s ;
-(NSString *) getfileName ;
#end
//
// File.m//
#import "File.h"
#implementation FileObj
-(void) setfileName:(NSString *)s ;
{
fileName=s;
}
-(NSString *) getfileName ;
{
return fileName;
}
#end
I initialize the myArray here:
NSMutableArray *temarray;
temarray=[[NSMutableArray alloc] init];
self.myArray=temarray;
[temarray release];
the codes to add object to myArray
FileObj *newobj=[[FileObj alloc]init ];
NSString *fieldValue2 = [[NSString alloc] initWithUTF8String:#"aaaa"];
[newobj setfileName:fieldValue2];
[myArray addObject:newobj];
[fieldValue2 release]; //**if I enabled the line, it will cause crash**
//**if I disable the line, it will cause memory leak**
[newobj release];
Welcome any comment
Thanks
interdev
First you should look into ObjC naming conventions. There is no -get methods in ObjC. It's also a good idea to prefix your classes with your own 2 letters (like NS).
Your setter value assignment is invalid and the NSString initialization unnecessary.
I would strongly recommend introductory material to you!
#interface MYFileObject : NSObject {
NSString *_fileName;
}
- (void)setFileName:(NSString *)theString;
- (NSString *)fileName;
#end
and the implementation
#implementation MYFileObject
- (void)setFileName:(NSString *)theString {
[_fileName release];
_fileName = [theString copy];
}
- (NSString *)fileName {
return [[_fileName copy] autorelease];
}
- (void)dealloc {
[_fileName release];
[super dealloc];
}
#end
You would add an object like this...
NSMutableArray *myAry = [[NSMutableArray alloc] init];
MYFileObject *obj = [[MYFileObject alloc] init];
[obj setFileName:#"thefilename.txt"];
[myAry addObject:obj];
[obj release];
I would recommend using properties instead of defining your own getters/setters.
You could also use the NSMutableArrays' designated initializers for fast array creation.
Look here for how to use properties: http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/ObjectiveC/Articles/ocProperties.html
Why bother with getters and setters? Use declared property already!
#interface FileObj : NSObject {
NSString *fileName;
}
#property(retain,nonatomic) NSString* fileName; // <---
#end
...
#implementation FileObj
#synthesize fileName; /// <---
-(void)dealloc {
[fileName release]; // Remember to release the object on dealloc.
[super dealloc];
}
#end
...
FileObj *newobj=[[FileObj alloc] init];
NSString *fieldValue2 = [[NSString alloc] initWithUTF8String:#"aaaa"];
newobj.fileName = fieldValue2; /// <----
[myArray addObject:newobj];
[fieldValue2 release];
[newobj release];
The crash occurs because the NSString instance is not retained anymore.
A common pattern is to retain NSString properties, either declaratively with #property or by hand.
You should modify the setter like this:
-(void) setfileName:(NSString *)s ;
{
[s retain]; // <- Retain new value
[filename release]; // <- Release old value
fileName=s;
}
Ok, I'm trying to avoid global variables, so I read up on singleton classes.
This is a try to set and read a mutable array, but the result is null.
//Content.h
#interface Content : NSObject {
NSMutableArray *contentArray;
}
+ (Content *) sharedInstance;
- (NSMutableArray *) getArray;
- (void) addArray:(NSMutableArray *)mutableArray;
#end
.
//Content.m
#implementation Content
static Content *_sharedInstance;
+ (Content *) sharedInstance
{
if (!_sharedInstance)
{
_sharedInstance = [[Content alloc] init];
}
return _sharedInstance;
}
- (NSMutableArray *) getArray{
return contentArray;
}
- (void) addArray:(NSMutableArray *)mutableArray{
[contentArray addObject:mutableArray];
}
#end
And in a ViewController I added #import "Content.h", where I try to call this:
NSMutableArray *mArray = [NSMutableArray arrayWithObjects:#"test",#"foo",#"bar",nil];
Content *content = [Content sharedInstance];
[content addArray:mArray];
NSLog(#"contentArray: %#", [content getArray]);
You need to alloc and init the array first. Personally I'd do it in the init method of the content class like so:
-(id)init{
if(self = [super init]){
…the rest of your init code…
contentArray = [[NSMutableArray alloc] init];
}
return self;
}
You never actually alloc/initialise the contentArray array.
I have a feeling that this is stupid question, but I'll ask anyway...
I have a collection of NSDictionary objects whose key/value pairs correspond to a custom class I've created, call it MyClass. Is there an easy or "best practice" method for me to basically do something like MyClass * instance = [map NSDictionary properties to MyClass ];? I have a feeling I need to do something with NSCoding or NSKeyedUnarchiver, but rather than stumble through it on my own, I figure someone out there might be able to point me in the right direction.
The -setValuesForKeysWithDictionary: method, along with -dictionaryWithValuesForKeys:, is what you want to use.
Example:
// In your custom class
+ (id)customClassWithProperties:(NSDictionary *)properties {
return [[[self alloc] initWithProperties:properties] autorelease];
}
- (id)initWithProperties:(NSDictionary *)properties {
if (self = [self init]) {
[self setValuesForKeysWithDictionary:properties];
}
return self;
}
// ...and to easily derive the dictionary
NSDictionary *properties = [anObject dictionaryWithValuesForKeys:[anObject allKeys]];
There is no allKeys on NSObject. You'll need to create an extra category on NSObject like below:
NSObject+PropertyArray.h
#interface NSObject (PropertyArray)
- (NSArray *) allKeys;
#end
NSObject+PropertyArray.m
#import <objc/runtime.h>
#implementation NSObject (PropertyArray)
- (NSArray *) allKeys {
Class clazz = [self class];
u_int count;
objc_property_t* properties = class_copyPropertyList(clazz, &count);
NSMutableArray* propertyArray = [NSMutableArray arrayWithCapacity:count];
for (int i = 0; i < count ; i++) {
const char* propertyName = property_getName(properties[i]);
[propertyArray addObject:[NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]];
}
free(properties);
return [NSArray arrayWithArray:propertyArray];
}
#end
Example:
#import "NSObject+PropertyArray.h"
...
MyObject *obj = [[MyObject alloc] init];
obj.a = #"Hello A"; //setting some values to attributes
obj.b = #"Hello B";
//dictionaryWithValuesForKeys requires keys in NSArray. You can now
//construct such NSArray using `allKeys` from NSObject(PropertyArray) category
NSDictionary *objDict = [obj dictionaryWithValuesForKeys:[obj allKeys]];
//Resurrect MyObject from NSDictionary using setValuesForKeysWithDictionary
MyObject *objResur = [[MyObject alloc] init];
[objResur setValuesForKeysWithDictionary:objDict];
Assuming that your class conforms to the Key-Value Coding protocol, you could use the following: (defined as a category on NSDictionary for convenience):
// myNSDictionaryCategory.h:
#interface NSDictionary (myCategory)
- (void)mapPropertiesToObject:(id)instance
#end
// myNSDictionaryCategory.m:
- (void)mapPropertiesToObject:(id)instance
{
for (NSString * propertyKey in [self allKeys])
{
[instance setValue:[self objectForKey:propertyKey]
forKey:propertyKey];
}
}
And here's how you would use it:
#import "myNSDictionaryCategory.h"
//...
[someDictionary mapPropertiesToObject:someObject];
If your doing this sort of thing chances are your dealing with JSON and you should probably have a look at Mantle
https://github.com/Mantle/Mantle
You will then get a convenient method dictionaryValue
[anObject dictionaryValue];
Just add category for NSObject for getting dictionaryRepresentation from your custom objects (in my case using in JSON serialization only):
// NSObject+JSONSerialize.h
#import <Foundation/Foundation.h>
#interface NSObject(JSONSerialize)
- (NSDictionary *)dictionaryRepresentation;
#end
// NSObject+JSONSerialize.m
#import "NSObject+JSONSerialize.h"
#import <objc/runtime.h>
#implementation NSObject(JSONSerialize)
+ (instancetype)instanceWithDictionary:(NSDictionary *)aDictionary {
return [[self alloc] initWithDictionary:aDictionary];
}
- (instancetype)initWithDictionary:(NSDictionary *)aDictionary {
aDictionary = [aDictionary clean];
self.isReady = NO;
for (NSString* propName in [self allPropertyNames]) {
[self setValue:aDictionary[propName] forKey:propName];
}
//You can add there some custom properties with wrong names like "id"
//[self setValue:aDictionary[#"id"] forKeyPath:#"objectID"];
self.isReady = YES;
return self;
}
- (NSDictionary *)dictionaryRepresentation {
NSMutableDictionary *result = [NSMutableDictionary dictionary];
NSArray *propertyNames = [self allPropertyNames];
id object;
for (NSString *key in propertyNames) {
object = [self valueForKey:key];
if (object) {
[result setObject:object forKey:key];
}
}
return result;
}
- (NSArray *)allPropertyNames {
unsigned count;
objc_property_t *properties = class_copyPropertyList([self class], &count);
NSMutableArray *rv = [NSMutableArray array];
unsigned i;
for (i = 0; i < count; i++) {
objc_property_t property = properties[i];
NSString *name = [NSString stringWithUTF8String:property_getName(property)];
[rv addObject:name];
}
//You can add there some custom properties with wrong names like "id"
//[rv addObject:#"objectID"];
//Example use inside initWithDictionary:
//[self setValue:aDictionary[#"id"] forKeyPath:#"objectID"];
free(properties);
return rv;
}
#end
Also, you can see that my solution will not work with custom objects with nested objects or arrays. For Arrays - just change the lines of code in dictionaryRepresentation method:
if (object) {
if ([object isKindOfClass:[NSArray class]]) {
#autoreleasepool {
NSMutableArray *array = [NSMutableArray array];
for (id item in (NSArray *)object) {
[array addObject:[item dictionaryRepresentation]];
}
[result setObject:array forKey:key];
}
} else {
[result setObject:object forKey:key];
}
}