NSString inheritance - objective-c

I'm doing an useless thing for my first step in Obj-C
#interface String : NSString
{
int m_isnull;
}
- (id) init;
- (int) isNull;
#end
#implementation String
- (id) init
{
self = [super init];
m_isnull=1;
return self;
}
- (int) isNull
{
return m_isnull;
}
#end
test :
String *a;
a=#"ok";
Works fine, but just 2 little questions
1) When I'm compiling I have this warning
warning: incompatible Objective-C types assigning 'struct NSString *', expected 'struct String *'
I don't know how to avoid it !?
2) a=#"ok" is a fastest way to initialize a string, but when I'm debugging, I don't stop by at my init constructor why ?

#"ok" is actually a NSString like 1 is an integer. That's why you get this compiler warning.
There are also #"" NSString literals.
It is essentially shorthand for
NSString's +stringWithUTF8String
method. Mac Player
already stated that it is used to
distinguish this sort of string
literal from a char * string literal
in C.
Source http://guides.macrumors.com/Objective-C_Tutorial#The_.40_symbol
Normally you would create a Category in Objective-C to extend the NSString Class.

Take a look at the NSString class reference:
It is possible to subclass NSString (and NSMutableString), but doing so requires providing storage facilities for the string (which is not inherited by subclasses) and implementing two primitive methods. The abstract NSString and NSMutableString classes are the public interface of a class cluster consisting mostly of private, concrete classes that create and return a string object appropriate for a given situation. Making your own concrete subclass of this cluster imposes certain requirements (discussed in “Methods to Override”).
If you really want to add an -isNull method to NSString you would probably be better off adding it as a category.
I think you might also want to try writing -(BOOL) isNotBlank instead. Consider what happens if you call -isNull on a nil pointer, is that the return value you would expect?

#"ok" is an NSString object. You're creating an instance of the superclass and trying to assign it to a subclass pointer. Think of subclassing as an "is-a" relationship. In your example, String is an NSString. NSString is not a String. Therefore, you can't assign an NSString object to a String pointer.

Related

How do I get the Objective-C class of an ivar?

I have a bunch of simple NSManagedObjects I create in a unit test. They just have a single name attribute of type NSString *. I always give my NSManagedObject the same entityName and Class name.
I want to avoid having to write the following code 30 times to set up a unit test:
#interface FooTest : GHTestCase {
Foo *foo;
}
#end
#implementation FooTest
- (void) setUp {
[super setUp];
foo = [NSEntityDescription insertNewObjectForEntityForName:#"Foo"
inManagedObjectContext:managedObjectContext];
foo.name = #"foo";
}
#end
Since foo is an ivar, I would think I should be able to write a macro to grab the type of foo (Foo), and use to create my Foo:
#define InsertManagedObjectByVariable(variable) \
do { \
variable = [NSEntityDescription insertNewObjectForEntityName:NSStringFromClass([typeof(variable) class])]; \
variable.name = (NSString *) CFSTR(#variable);
} while(0)
However, this causes the following warning in clang:
variable = [NSEntityDescription insertNewObjectForEntityName:NSStringFromClass([typeof(variable) class])];
^
Expected expression
I also thought I could try to determine the type using the objective-c runtime IVar from Ivar class_getInstanceVariable(Class cls, const char* name), but the only IVar type information available from the type encoding from ivar_getTypeEncoding is id, which isn't enough.
Can someone think of a way to obtain the type information of an IVar either at compile time or runtime?
I haven't tried obtaining class information from an ivar, but I know that #property declarations do encode information about the class. For instance, this property declaration:
#property (copy) NSString *normalString;
results in this attribute string (retrieved using property_getAttributes()) at runtime:
T#"NSString",C,VnormalString
I've written some open source parsing code for this information.
Once you have the class name, you can convert it into an actual Class object using NSClassFromString(), and message the result from there.
Disclaimer: This probably shouldn't be depended upon for production applications, as it is undocumented.
An id is an id. At runtime, all Objective-C objects have the same type (objc_object). This is tied up in the dynamic nature of ObjC. For example, an object can change classes at runtime, new classes can be created, and the class hierarchy can change. You can ask a specific instance what its type is (since this is stored in objc_object), but a pointer to an object is just a pointer to an object. Even less than that: it's really just a pointer to a C struct that happens to have extra memory allocated at the end (to hold subclass ivars).
Your macro seems interesting, but you'll probably need to pass the classname as the second parameter rather than autodetecting it.
Maybe i misunderstand what you are trying to achieve.
To get the class of an iVar, can't you use the class method of the iVar?
like:
NSString *aString = #"random string";
NSLog(#"%#",NSStringFromClass([aString class]));

Why am I getting "incompatible pointer type"?

I am trying to create a custom object that simply inherits the NSString class and overrides the 'description' method.
When I compile, however, I am getting a warning:
Incompatible pointer types initializing 'OverrideTester *' with an expression of type 'NSString *'
Here is my code:
main.m
#import <Foundation/NSObject.h>
#import <Foundation/NSString.h>
#import <Foundation/NSAutoreleasePool.h>
#import "OverrideTester.h"
int main (int argc, char *argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *str = #"Programming is fun";
OverrideTester *strOverride = #"Overriding is fun";
NSLog (#"%#", str);
NSLog (#"%#", strOverride);
[pool drain];
return 0;
}
OverrideTester.h
#import <Foundation/Foundation.h>
#interface OverrideTester : NSString
-(void) description;
#end
OverrideTester.m
#import "OverrideTester.h"
#implementation OverrideTester
-(void) description
{
NSLog(#"DESCRIPTION!\n");
}
#end
NSString is part of a class cluster. You cannot just create arbitrary subclasses of it, and when you do, you can't assign constant strings to them (which are type NXConstantString). See Subclassing Notes in the NSString documentation. Generally you don't want to subclass NSString. There are better solutions for most problems.
you are assigning an instance of NSString to your variable of type OverrideTester. If you want an instance of your class, you need to instantiate an instance of that class; type-casting will never change the class of an instance.
description is defined as returning an NSString*:
- (NSString *)description;
Do not try to learn about subclassing and overriding methods by subclassing NSString (or any other class cluster). If you want to play with subclassing and such -- a very good idea when new to the language, assuredly -- then subclass NSObject, potentially multiple levels , and play there.
How do you mean to subclass NSObject,
potentially multiple levels? Isn't it
possible NSObject might have
conflicting methods compared to other
class clusters or just not have them
available to override?
If your goal is to figure out how method overrides work (which I thought it was), then you'd be better off doing it entirely yourself.
I may have mis-read your question.
In any case, subclassing NSString is pretty much never done. There are very very few cases where it is useful. Overriding description in anything but custom classes specifically for debugging purposes is useful, yes. Calling description in production code should never be done.
Also, why would description return an
NSString* in this code?
What would happen if something that expects an NSString* return value were to call your version that doesn't return anything?
A crash.
You are declaring a variable named strOverride of type pointer to OverrideTester. But to that variable, you are trying to assign a pointer to an NSString. You cannot assign a superclass to a variable of a subclass. Imagine a generic class TwoWheeled and a derived class Motorbike. A Motorbike can be treated like a TwoWheeled, but not the other way round as the Motorbike has features a normal TwoWheeled might not have like a motor.

Objective-C constants in protocol

In my objective-c project, I have a protocol like this:
#protocol MyProtocol
-(id) get:(NSString *) key;
-(void) set:(NSString *) key withValue:(id) value;
-(NSValue *) getSize;
-(void) setSize:(NSValue *) value;
-(NSValue *) getBounds;
-(void) setBounds:(NSValue *) value;
#end
OBJC_EXPORT const NSString *MYPROTOCOL_SIZE;
OBJC_EXPORT const NSString *MYPROTOCOL_BOUNDS;
And basically, those specific methods (getSize, getBounds, setSize, setBounds) are supposed the value that is supposed to be stored in MYPROTOCOL_SIZE and MYPROTOCOL_BOUNDS, respectively.
However, I cannot find an effective way to set those constant strings, by concatenating the results of other methods, because it gives me the error: initializer element is not constant when I try to set them directly. Is there a way I can guarantee that the objects will always be initialized. (e.g. in a classes load method), without having to manually call code when my program runs?
Well first of all, you should learn the naming convention, for accessors you have - (Type); and - (void)set:(Type)value; whereas in your case you did: - (Type)get; and - (void)set:(Type)value;
I advise you to use #property for your size and bounds accessors too.
Now about the "const" in the NSString variable declaration, it doesn't make sense. Const applies to the type on its left and in case it is at the beginning of the line it applies to the token directly on its right. So what you have is a "const NSString" which doesn't make sense because NSString is already immutable, and sending mutating messages to a const object doesn't issue any warning or errors...
What you actually want is "NSString *const" which states that the pointer to your NSString is constant, you can only assign it at initialization and then it doesn't change...
Now about the protocol... Are you sure you want a protocol in your case ? And not an abstract class that would have your 2 NSString as readonly accessors ?

Can someone explain to me what (NSString *) means with Obj-C?

I just started with Objective-C and I would like to understand the meaning of the following lines of code as I see it everywhere in objective-c but I'm not quite getting it 100%:
- (id)initWithName:(NSString *)name;
I understand that the above line is a instance method passing one argument, what I don't understand is (NSString *)name.
another example is:
-(NSString *)name;
or
person.height = (NSObject *)something;
Thanks for your help
In this line:
- (id)initWithName:(NSString *)name;
(NSString *) is simply the type of the argument - a string object, which is the NSString class in Cocoa. In Objective-C you're always dealing with object references (pointers), so the "*" indicates that the argument is a reference to an NSString object.
In this example:
person.height = (NSObject *)something;
something a little different is happening: (NSObject *) is again specifying a type, but this time it's a "type casting" operation -- what this means is to take the "something" object reference (which could be an NSString, NSNumber, or ...) and treat it as a reference to an NSObject.
update -
When talking about Objective-C objects (as opposed to primitive types like int or float), everything's ultimately a pointer, so the cast operation means "take this pointer an X and treat it as if it's pointing to a Y". For example, if you have a container class (like NSArray) that holds generic NSObjects, but you know that the the objects are actually strings, you might say:
NSString *myString = (NSString *)[myArray objectAtIndex:0];
which means "retrieve the first object from the array, treating it as a string".
The cast is not actually converting the value, it's just a way of saying to the compiler "hey, I know that I'm assigning an X to a Y here, so don't give me a warning about it".
- (id)initWithName:(NSString*)name;
Is a signature of a method that takes one parameter called name which is a pointer to NSString.
-(NSString *)name;
Is an accessor method called name that returns pointer to NSString.
person.height = (NSObject *)something;
Typecasts something to a NSObject pointer and then it is assigned to person.height property.
See more explanation in Learning Objective-C: A Primer
- (id)initWithName:(NSString *)name;
-----------------------------------------
'-' means its an instance method (+ is used for static methods)
'(id)' is the return type
'initWithName' is the function name, the name implies its a constructor
':' start of parameter
'(NSString*)' parameter type
'name' parameter name
its the equivalent of
(id)initWithName( NSString* name )
(NSString *)name
is saying that a variable name is a pointer * to a NSString object. Its a pointer because the name variable isn't the string but rather it is just the address in memory for that string.

Why use (id) in a method signature when (NSObject *) would be more precise?

Whenever I implement a method in my own code that can accept or return objects of more than one class, I always try to use the most specific superclass available. For example, if I were going to implement a method that might return an NSArray * or an NSDictionary * depending on its input, I would give that method a return type of NSObject *, since that's the most direct common superclass. Here's an example:
#interface MyParser()
- (BOOL)stringExpressesKeyValuePairs:(NSString *)string;
- (BOOL)stringExpressesAListOfEntities:(NSString *)string;
- (NSArray *)parseArrayFromString:(NSString *)string;
- (NSDictionary *)parseDictionaryFromString:(NSString *)string;
#end
#implementation MyParser
- (NSObject *)parseString:(NSString *)string {
if ([self stringExpressesKeyValuePairs:string]) {
return [self parseDictionaryFromString:string];
}
else if ([self stringExpressesAListOfEntities:string]) {
return [self parseArrayFromString:string];
}
}
// etc...
#end
I've noticed many cases in Foundation and other APIs where Apple uses (id) in certain method signatures when (NSObject *) would be more precise. For example, here's a method of NSPropertyListSerialization:
+ (id)propertyListFromData:(NSData *)data
mutabilityOption:(NSPropertyListMutabilityOptions)opt
format:(NSPropertyListFormat *)format
errorDescription:(NSString **)errorString
The possible return types from this method are NSData, NSString, NSArray, NSDictionary, NSDate, and NSNumber. It seems to me that a return type of (NSObject *) would be a better choice than (id), since the caller would then be able to call NSObject methods like retain without a type-cast.
I generally try to emulate the idioms established by the official frameworks, but I also like to understand what motivates them. I'm sure that Apple has some valid reason for using (id) in cases like this, but I'm just not seeing it. What am I missing?
The reason why (id) is used in method declarations is two fold:
(1) The method may take or return any type. NSArray contains any random object and, thus, objectAtIndex: will return an object of any random type. Casting it to NSObject* or id <NSObject> would be incorrect for two reasons; first, an Array can contain non NSObject subclasses as long as they implement a certain small set of methods and, secondly, a specific return type would require casting.
(2) Objective-C doesn't support covariant declarations. Consider:
#interface NSArray:NSObject
+ (id) array;
#end
Now, you can call +array on both NSArray and NSMutableArray. The former returns an immutable array and the latter a mutable array. Because of Objective-C's lack of covariant declaration support, if the above were declared as returning (NSArray*), clients of the subclasses method would have to cast to `(NSMutableArray*). Ugly, fragile, and error prone. Thus, using the generic type is, generally, the most straightforward solution.
So... if you are declaring a method that returns an instance of a specific class, typecast explicitly. If you are declaring a method that will be overridden and that override may return a subclass and the fact that it returns a subclass will be exposed to clients, then use (id).
No need to file a bug -- there are several already.
Note that ObjC now has limited co-variance support through the instancetype keyword.
I.e. NSArray's +array method could now be declared as:
+ (instancetype) array;
And the compiler would treat [NSMutableArray array] as returning an NSMutableArray* while [NSArray array] would be considered as returning NSArray*.
Using id tells the compiler it will be an object of unknown type. Using NSObject the compiler would then expect you to only be using messages available to NSObject. So... If you know an array was returned and it's casted as id, you can call objectAtIndex: without compiler warnings. Whereas returning with a cast of NSObject, you'll get warnings.
You can already call -retain on pointers of type id without casting. If you use a specific superclass type, you'll have to cast the pointer every time you call a subclass's method in order to avoid compiler warnings. Use id so the compiler won't warn you and to better signify your intent.
(id) is also often returned in order to enable objects to be subclassed more easily. For instance, in initializer and convenience methods, returning (id) means that any subclass doesn't have to override the superclass's methods unless there is a specific reason to do so.