Subclass NSString - iphone

I want to add a property to a NSString object. For this reason I want to subclass it.
I try to make something like this:
#interface MyString : NSString
#property (nonatomic) NSInteger userId;
#end
so then I can do
MyString *testString = [[MyString alloc] init];
testString = [MyString stringWithFormat:#"hello"];
testString.userId = 2;
NSLog(#"testString: %#", testString); //-> Want it to return "testString: hello"
NSLog(#"userId: %d", testString.userId); //-> Want it to return "userId: 2"
I don't know how to subclass NSString (create storage facilities, override some methods (length, characterAtIndex). Have an idea?

Don't try to subclass NSString to do this. Create an entirely new class that is a subclass of NSObject and give it 2 properties (and a set of methods to access the properties if you want to).
Trying to use NSString is overly complicated and not appropriate.
For this line:
NSLog(#"testString: %#", testString);
all you need to do is implement the description method on your custom class to return the string property. Then the string will be printed when you use NSLog.

Subclassing class cluster classes is tricky, as you've discovered. Which is why, generally, it is pretty much never done.
Instead, create a class that encapsulates two strings; the string that would point to #"hello" in your example and the userId.
#interface MyThingy:NSObject
#property(copy) NSString *stringData;
#property(copy) NSString *userId;
#end
... etc ...
This will be far more flexible and it will be easier to refactor in the future.
BTW, this doesn't make sense:
MyString *testString = [[MyString alloc] init];
testString = [MyString stringWithFormat:#"hello"];
Under manual retain/release, it is a leak. Under ARC, it is a purposeless allocation.

Why don't you use NSMutablestring in this you can use appendString method in which you can add your any stringValue and then just pass the same to your string.

Try this category. You can add any kind of custom object to anything coming from NSObject - basically any class - by use of a key. Retrieve the object using that key. I think I got this from someone (found it) here on stackoverflow.
Header:
//
// NSObject+arbitraryobjectonanynsobjectlol.h
//
//
// Created by someone on 2/21/14.
// Copyright (c) 2014 someone. All rights reserved.
//
#import <Foundation/Foundation.h>
// https://stackoverflow.com/a/10319083/129202
#interface NSObject (arbitraryobjectonanynsobjectlol)
- (id)associativeObjectForKey: (NSString *)key;
- (void)setAssociativeObject: (id)object forKey: (NSString *)key;
#end
And the implementation:
//
// NSObject+arbitraryobjectonanynsobjectlol.m
// someone
//
// Created by someone on 2/21/14.
// Copyright (c) 2014 someone. All rights reserved.
//
#import "NSObject+arbitraryobjectonanynsobjectlol.h"
#import <objc/runtime.h>
#implementation NSObject (arbitraryobjectonanynsobjectlol)
static char associativeObjectsKey;
- (id)associativeObjectForKey: (NSString *)key {
NSMutableDictionary *dict = objc_getAssociatedObject(self, &associativeObjectsKey);
return [dict objectForKey: key];
}
- (void)setAssociativeObject: (id)object forKey: (NSString *)key {
NSMutableDictionary *dict = objc_getAssociatedObject(self, &associativeObjectsKey);
if (!dict) {
dict = [[NSMutableDictionary alloc] init];
objc_setAssociatedObject(self, &associativeObjectsKey, dict, OBJC_ASSOCIATION_RETAIN);
} [dict setObject: object forKey: key];
}
#end

Related

How to use methods from NSManagedObject entity using NSManagedObject

I am using a NSManagedObject to save some values, but not using entity for that. Because I want to not limit it to some entities. I tried using (Oist *)managedObject.entity, not working. How to use this managedObject to get theIt's like this:
Oist.h
#class File;
#interface Oist : NSManagedObject
#property (nonatomic, retain) NSSet *files;
#end
#interface Oist (CoreDataGeneratedAccessors)
- (void)addFilesObject:(File *)value;
File.h
#class Oist;
#interface File : NSManagedObject
#property (nonatomic, retain) Oist *gist;
#end
- (void)newManagedObjectWithClassName:(NSString *)className forRecords:(NSDictionary *)records
{
NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:className inManagedObjectContext:[[GPCoreDataController sharedInstance] backgroundManagedObjectContext]];
[records enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
[self setValue:obj forKey:key forManagedObject:newManagedObject];
}];
}
- (void)setValue:(id)value forKey:(NSString *)key forManagedObject:(NSManagedObject *)managedObject
{
File *fileEntity = [NSEntityDescription insertNewObjectForEntityForName:#"File" inManagedObjectContext:[[GPCoreDataController sharedInstance] backgroundManagedObjectContext]];
if ([key isEqualToString:#"files"])
{
NSDictionary *files = (NSDictionary *)value;
for (NSString *key in [files allKeys]) {
NSDictionary *file = [files valueForKey:key];
NSLog(#"%#", file[#"filename"]);
[fileEntity setValue:file[#"filename"] forKey:#"filename"];
[fileEntity setValue:file[#"type"] forKey:#"type"];
}
} else if ([key isEqualToString:#"id"])
{
if ([managedObject.entity.name isKindOfClass:[Oist class]]) {
//here I want to use Oist's method - (void)addFilesObject:(File *)value; how to do that?
}
[managedObject setValue:[NSNumber numberWithInt:[value integerValue]] forKey:#"gistID"];
}
}
I may be misunderstanding your question, but it looks like you're hoping to cast a generically typed (NSManagedObject *) as a more specifically typed subclass.
The way to check if the pointer passed generically is in fact an instance of your subclass is this:
if ([managedObject isKindOfClass:[Oist self]]) {
// managedObject may safely be cast to an Oist*
}
You can do the cast without an assignment, like this:
[(Oist *)managedObject addFiles...];
Or, with proper parentheses, access a property (the dot operator has higher precedence than the cast, so you need to tell the compiler you want the cast first):
((Oist *)managedObject).entity
But I think that's less clear to the reader and potentially more keystrokes than an explicit assignment with a cast, which is what I'd recommend:
if ([managedObject isKindOfClass:[Oist self]]) {
Oist *oist = (Oist *)managedObject;
[oist addFilesObject:someFilesObject];
}

objective c how to create dictionaries dynamically and refer to them

i need to create and destroy dynamically dictionaries, or arrays,
and have them as instance variables,
so for example, [pseudocode]
*.h
nsmutableDictionary myDictn???
nsstring arrayn ???
how to create an instance dictionarie, and property, that dinamically get created and destroyed?, and how to refer to it?
*.m
n = 0
create container {
myDictn alloc init
n+1
}
other {
myDictn addobject#"data" forKey"myKey"
}
destroy container {
myDictn release
n-1
}
So what intend to show is that i would like to have myDict1, myDict2...
if created,
or destroy them if needed
thanks a lot!
To create dictionaries dynamically & add entries to them you could do this -
NSMutableDictionary *dictResult = [[[NSMutableDictionary alloc] init] retain];
[dictResult setValue:result forKey:#"key"];
Here result can be anything. NSString or NSArray etc. Also using retain retains this object & causes a memory leak if not explicitly released. Instead try to do autorelease that way ios takes care of releasing the object when its no longer referred to. You do that like so -
NSMutableDictionary *dictResult = [[[NSMutableDictionary alloc] init] autorelease];
This is all you need to create dictionaries dynamically.
I think what you're asking for is how to have multiple mutable dictionaries dynamically created. You haven't said where the numbering scheme is coming from, so you may need to modify this solution for your purposes.
What you want is an array or dictionary of dictionaries.
Make one NSMutableDictionary called something like dictionaryContainer. Then, when you want to create dictionary number 7, do
NSMutableDictionary *aDictionary = [NSMutableDictionary new];
[dictionaryContainer setObject:aDictionary forKey:[NSNumber numberWithInt:7]];
To recall that dictionary, do
NSMutableDictionary *theSameDictionary = [dictionaryContainer objectForKey:[NSNumber numberWithInt:7]];
You don't have to hard code the 7, you can get it from anywhere and pass it in as an integer variable.
If I got your question correctly, this is pretty easy
#interface MyClass {
NSMutableDictionary *dict;
NSMutableArray *arr;
}
#property (nonatomic, retain) NSMutableDictionary *dict;
#property (nonatomic, retain) NSMutableArray *arr;
#end
Implementation file
#import "MyClass.h"
#implementation MyClass
#synthesize dict;
#synthesize arr;
- (id) init {
self = [super init];
if (self) {
dict = [[NSMutableDictionary alloc] init];
arr = [[NSMutableArray alloc] init];
}
return self;
}
- (void) dealloc {
[dict release];
[arr release];
[super dealloc];
}
- (void) otherStuff {
[dict setObject: #"value" forKey: #"key"];
[arr addObject: #"item"];
}
#end
usage from another class:
...
MyClass *instance = [MyClass new];
[instance.dict setObject: #"value" forKey: #"key"];
NSLog(#"Array items: %#", instance.arr);
[instance release];
...

how do I build up a global like integer array?

How do I build up a global like integer array?
I tried variations of the following:
#interface
int *iArray; //this space will vary depending upon need in the implementation
#implementation
...
int iArrayInit[4] = {1,2,3,4};
iArray = iArrayInit;
-bottom line: I need to keep index values in array that I can access easily, and use of [NSArray intValue] maybe to slow.
thanks
If it needs to be static you can declare an NSMutableArray as static in the implementation file and expose static methods to access it. When using an NSArray the values need to be of type id which NSNumber can do. Here is an example which currently is not thread safe.
//.h file
#interface Foo : NSObject
{
}
+(NSArray*)iArray;
+(void)addiArrayValue:(NSNumber*)value;
#end
//.m file
#implementation Foo
static NSMutableArray *_iArray;
+(void)initialize
{
if([Foo class] == self)
{
_iArray = [[NSMutableArray alloc] init];
}
}
+(NSArray*)iArray
{
return [[_iArray copy] autorelease];
}
+(void)addiArrayValue:(NSNumber*)value
{
[_iArray addObject:value];
}
#end
//Use
[Foo addiArrayValue:[NSNumber numberWithInt:10]];
[Foo addiArrayValue:[NSNumber numberWithInt:12]];
NSLog(#"%#", [Foo iArray]);

Method '-cleanTitle.' not found (return type defaults to 'id')

I'm trying to implement an rss feed into my app and I have created a method to clean the title up.
- (NSString *)cleanTitle:(NSString *)Title {
return [Title stringByReplacingOccurrencesOfString:#"twitterfeed: " withString:#""];
}
The warning occurs on the articleTitle line below:
- (void)parseAtom:(GDataXMLElement *)rootElement entries:(NSMutableArray *)entries {
NSString *blogTitle = [rootElement valueForChild:#"title"];
NSArray *items = [rootElement elementsForName:#"entry"];
for (GDataXMLElement *item in items) {
NSString *articleTitle = [self cleanTitle: [item valueForChild:#"title"]];
Do you know how to get rid of this warning?
Thanks.
Make sure - (NSString *)cleanTitle:(NSString *)Title is also declared in your header file.
The method's signature must be known before it is used if the two methods are not in the same category or class. If it's the same class but -cleanTitle: is in a (Private) category or some such, be sure to declare that category prior to your class' implementation (in your .m file) :
#interface MyClass (Private)
- (NSString *)cleanTitle: (NSString *)title;
#end

#dynamic properties and its usage?

Can anyone give me clear picture about dynamic property and its usage? y not use the usual #property everywhere?
Dynamic properties are used when you don't provide an implementation at compile time, but ensure that one exists at runtime. Being a dynamic language, Objective-C can respond to messages at runtime, even if the class doesn't have an implementation at compile time.
Here's a contrived example: Let's say you have a Book class, backed by an NSMutableDictionary that contains the keys title and author. However, you want Book to respond to title and author as well, and have them as properties; title and author will grab the appropriate value from the dictionary, and setTitle: and setAuthor: will change the value stored in the dictionary. You could do so with this code:
#import <Foundation/Foundation.h>
#interface Book : NSObject
{
NSMutableDictionary *data;
}
#property (retain) NSString *title;
#property (retain) NSString *author;
#end
#implementation Book
#dynamic title, author;
- (id)init
{
if ((self = [super init])) {
data = [[NSMutableDictionary alloc] init];
[data setObject:#"Tom Sawyer" forKey:#"title"];
[data setObject:#"Mark Twain" forKey:#"author"];
}
return self;
}
- (void)dealloc
{
[data release];
[super dealloc];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
{
NSString *sel = NSStringFromSelector(selector);
if ([sel rangeOfString:#"set"].location == 0) {
return [NSMethodSignature signatureWithObjCTypes:"v#:#"];
} else {
return [NSMethodSignature signatureWithObjCTypes:"##:"];
}
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
NSString *key = NSStringFromSelector([invocation selector]);
if ([key rangeOfString:#"set"].location == 0) {
key = [[key substringWithRange:NSMakeRange(3, [key length]-4)] lowercaseString];
NSString *obj;
[invocation getArgument:&obj atIndex:2];
[data setObject:obj forKey:key];
} else {
NSString *obj = [data objectForKey:key];
[invocation setReturnValue:&obj];
}
}
#end
int main(int argc, char **argv)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Book *book = [[Book alloc] init];
printf("%s is written by %s\n", [book.title UTF8String], [book.author UTF8String]);
book.title = #"1984";
book.author = #"George Orwell";
printf("%s is written by %s\n", [book.title UTF8String], [book.author UTF8String]);
[book release];
[pool release];
return 0;
}
Note the the methods are "created" at runtime via forwardInvocation:; hence, title and author are dynamic properties.
(This isn't the best example, but I think it gets the point across.)
#dynamic thing; is merely a way to inform the system not to generate getters/setters for the thing, that you (or someone else) will provide them for you—As in, they'll be there at runtime.
This is in contrast to #synthesize which tells the compiler to generate the getter/setter (as appropriate) for you.
#dynamic is (in my experience) used primarily in conjunction with Core Data and subclasses of NSManagedObject. To quote Marcus Zarra's Core Data,
By declaring them
[attributes/relationships], we are
telling the compiler to ignore any
warnings associated with there
properties because we "promise" to
generate them at runtime. Naturally,
if the turn up missing at runtime,
then our application is going to
crash.