0

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?

Gabriel
  • 2,331
  • 2
  • 13
  • 18

4 Answers4

7

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.

Wain
  • 118,658
  • 15
  • 128
  • 151
  • Thank you. I need it to use a library that provide token fields for choosing contacts (like in the SMS application from apple). I provide it an array of name, but I'd like to keep the id of the person (as a property of the name of a person). I don't want to override the description method as the goal is not to print in the console. – Gabriel Oct 19 '13 at 19:00
  • Associated objects are also an option, but maybe too sophisticated for this simple use case. – Gabriele Petronella Oct 19 '13 at 19:03
  • Why don't you just us a dictionary which maps the names to the identities? – Wain Oct 19 '13 at 19:06
  • I currently use a similar trick. But I have some people that have the same name. – Gabriel Oct 19 '13 at 19:08
  • So you should really be modifying the library you're using if you can have multiple strings that are the same (because you need to uniquely identify the tokens and that should be done by the id). It's unlikely to be hard to modify the library. – Wain Oct 19 '13 at 19:10
5

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.

bbum
  • 162,346
  • 23
  • 271
  • 359
  • Ok thank you you, but is there a way to return the NSString stringData when my object is called? Without having to precise nameOfTheObject.stringData ? – Gabriel Oct 19 '13 at 19:02
  • You'll have to define what `when my object is called` means. But, in general, no, and that is by design. A String is intended to be a single, cohesive, nugget of data with no attached functionality beyond encapsulating strings. It is a primitive like NSDate or NSNumber. While it may be a couple of more lines of code here and there, treating it thusly will lead to a vastly more robust and consistent application design. – bbum Oct 19 '13 at 22:09
0

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.

Hussain Shabbir
  • 14,801
  • 5
  • 40
  • 56
0

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
Community
  • 1
  • 1
Jonny
  • 15,955
  • 18
  • 111
  • 232