Related
I know Apple has cautioned against using it. But given their reasoning, the results are far from relevant and expected.
Here is my debug output - the results aren't different in code - below is just for brevity:
(lldb) po [#"Hello" isKindOfClass:[NSMutableString class]]
true => A mutable string?
(lldb) po [[#"Hello" mutableCopy] isKindOfClass:[NSMutableString class]]
0x00000001019f3201 => What's that?
(lldb) po [[#"Hello" mutableCopy] isMemberOfClass:[NSMutableString class]]
0x000000010214e400 => What's that?
(lldb) po [#"Hello" isMemberOfClass:[NSMutableString class]]
false => Once again?
Further to that, I removed all the string literal code and tested the following:
NSMutableString * m = [[NSMutableString alloc] initWithString:#"Hello"];
bool b = [m isKindOfClass:[NSMutableString class]];
NSLog(#"%d", b); --> 1 Expected.
b = [m isKindOfClass:[NSString class]];
NSLog(#"%d", b); --> 1 Expected.
b = [m isMemberOfClass:[NSString class]];
NSLog(#"%d", b); --> 0 Expected.
b = [m isMemberOfClass:[NSMutableString class]];
NSLog(#"%d", b); --> 0 Not Expected.
Is there an enlightenment?
UPDATE:
Apple's own take:
Be careful when using this method on objects represented by a class
cluster. Because of the nature of class clusters, the object you get
back may not always be the type you expected. If you call a method
that returns a class cluster, the exact type returned by the method is
the best indicator of what you can do with that object.
Why not simply say do not employ isKindOfClass and isMemberOfClass with cluster classes?
The explanation prevents use from the perspective such as:
You might end up modifying something that you are not supposed to.
instead of stating:
These methods do not work with class clusters.
(in the examples, I have shown above - I am clearly passing correct objects and still not getting expected results.)
UPDATE 2:
Filed with Apple Radar.
The methods don't "mislead" as you claim in the comments. Because NSString and NSMutableString are class clusters, they can return an instance of any concrete subclass that is-a NSString or NSMutableString, respectively.
As it happens, most concrete subclasses in the NSString cluster are also subclasses of NSMutableString. Instead of using the actual class to control mutability, they use a flag or something like that. All perfectly valid and complying with the design contract.
So, that's why [#"Hello" isKindOfClass:[NSMutableString class]] returns true. You ask "A mutable string?" No. That expression is not a valid test of mutability. As documented, there is no valid test of mutability. This is at the core of your misunderstanding. You must not attempt to interrogate the class of an object to determine if it's mutable. You must respect the static type of the pointer in the API.
Edit: This is documented in Concepts in Objective-C Programming: Object Mutability – Receiving Mutable Objects:
Use Return Type, Not Introspection
To determine whether it can change a received object, the receiver of
a message must rely on the formal type of the return value. If it
receives, for example, an array object typed as immutable, it should
not attempt to mutate it. It is not an acceptable programming practice
to determine if an object is mutable based on its class membership—for
example:
if ( [anArray isKindOfClass:[NSMutableArray class]] ) {
// add, remove objects from anArray
}
For reasons related to implementation, what isKindOfClass: returns in
this case may not be accurate. But for reasons other than this, you
should not make assumptions about whether an object is mutable based
on class membership. Your decision should be guided solely by what the
signature of the method vending the object says about its mutability.
If you are not sure whether an object is mutable or immutable, assume
it’s immutable.
A couple of examples might help clarify why this guideline is
important:
You read a property list from a file. When the Foundation framework processes the list, it notices that various subsets of the
property list are identical, so it creates a set of objects that it
shares among all those subsets. Afterward you look at the created
property list objects and decide to mutate one subset. Suddenly, and
without being aware of it, you’ve changed the tree in multiple places.
You ask NSView for its subviews (with the subviews method) and it returns an object that is declared to be an NSArray but which could be
an NSMutableArray internally. Then you pass that array to some other
code that, through introspection, determines it to be mutable and
changes it. By changing this array, the code is mutating internal data
structures of the NSView class.
So don’t make an assumption about object mutability based on what
introspection tells you about an object. Treat objects as mutable or
not based on what you are handed at the API boundaries (that is, based
on the return type). If you need to unambiguously mark an object as
mutable or immutable when you pass it to clients, pass that
information as a flag along with the object.
As others have mentioned, -isMemberOfClass: tests for being an instance of that exact class and not any subclass. For a class cluster, that will always return false, because the public class is abstract and will never have instances.
The other weird results are probably because you're using po (short for "print object") for non-object values. Use the p command for boolean expressions.
tl;dr Don't use introspection in your code to determine mutability or to vary behavior (outside of extremely limited situations). Do use static types and strongly defined data structures (including strongly defined plist structures).
The introspection functionality offered by the Objective-C runtime, of which the introspection methods on NSObject are implemented against, are neither misleading nor are they returning incorrect results.
They are revealing specific details of how the various objects are implemented. This may appear quite different from what is declared in the header files.
Or, to put it another way: compile time vs. run time may be very different.
That is both correct and OK. And confusing.
Objective-C implements a strong notion of duck typing. That is, if you have a reference to something declared as NSString*, it really doesn't matter what that reference really points to as long is it responds to the API contract declared for the class NSString.
The confusion comes from trying to treat Objective-C as a fully dynamic, introspection driven, language. It wasn't designed for that (well, it kinda was, but that notion was dropped by about 1990) and, over time, strong typing has become more and more the norm. I.e. let the compiler figure out if something is valid and don't try to second guess at runtime.
I'm new to Mac/iPhone programming and Objective-C. In C# and Java we have "generics", collection classes whose members can only be of the type declared. For example, in C#
Dictionary<int, MyCustomObject>
can only contain keys that are integers and values that are of type MyCustomObject. Does a similar mechanism exist in Objective-C?
In Xcode 7, Apple has introduced 'Lightweight Generics' to Objective-C. In Objective-C, they will generate compiler warnings if there is a type mismatch.
NSArray<NSString*>* arr = #[#"str"];
NSString* string = [arr objectAtIndex:0];
NSNumber* number = [arr objectAtIndex:0]; // Warning: Incompatible pointer types initializing 'NSNumber *' with an expression of type 'NSString *'
And in Swift code, they will produce a compiler error:
var str: String = arr[0]
var num: Int = arr[0] //Error 'String' is not convertible to 'Int'
Lightweight Generics are intended to be used with NSArray, NSDictionary and NSSet, but you can also add them to your own classes:
#interface GenericsTest<__covariant T> : NSObject
-(void)genericMethod:(T)object;
#end
#implementation GenericsTest
-(void)genericMethod:(id)object {}
#end
Objective-C will behave like it did before with compiler warnings.
GenericsTest<NSString*>* test = [GenericsTest new];
[test genericMethod:#"string"];
[test genericMethod:#1]; // Warning: Incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString *'
but Swift will ignore the Generic information completely. (No longer true in Swift 3+.)
var test = GenericsTest<String>() //Error: Cannot specialize non-generic type 'GenericsTest'
Aside from than these Foundation collection classes, Objective-C lightweight generics are ignored by Swift. Any other types using lightweight generics are imported into Swift as if they were unparameterized.
Interacting with Objective-C APIs
This answer is outdated but remains for historical value. As of Xcode 7, Connor's answer from Jun 8 '15 is more accurate.
No, there are no generics in Objective-C unless you want to use C++ templates in your own custom collection classes (which I strongly discourage).
Objective-C has dynamic typing as a feature, which means that the runtime doesn't care about the type of an object since all objects can receive messages. When you add an object to a built-in collection, they are just treated as if they were type id. But don't worry, just send messages to those objects like normal; it will work fine (unless of course one or more of the objects in the collection don't respond to the message you are sending).
Generics are needed in languages such as Java and C# because they are strong, statically typed languages. Totally different ballgame than Objective-C's dynamic typing feature.
No, but to make it clearer you can comment it with the type of object you want to store, I've seen this done a few times when you need to write something in Java 1.4 nowadays) e.g.:
NSMutableArray* /*<TypeA>*/ arrayName = ....
or
NSDictionary* /*<TypeA, TypeB>*/ dictionaryName = ...
This was released in Xcode 7 (finally!)
Note that in Objective C code, it's just a compile-time check; there will be no run-time error just for putting the wrong type into a collection or assigning to a typed property.
Declare:
#interface FooClass <T> : NSObject
#property (nonatomic) T prop;
#end
Use:
FooClass<NSString *> *foo = [[FooClass alloc] init];
NSArray<FooClass<NSString *> *> *fooAry = [NSArray array];
Be careful about those *s.
There are no generics in Objective-C.
From the Docs
Arrays are ordered collections of objects. Cocoa provides several array classes, NSArray, NSMutableArray (a subclass of NSArray), and NSPointerArray.
Apple has added generics to ObjC in XCode 7:
#property NSArray<NSDate *>* dates;
- (NSArray<NSDate *> *)datesBeforeDate:(NSDate *)date;
- (void)addDatesParsedFromTimestamps:(NSArray<NSString *> *)timestamps;
see here:
https://developer.apple.com/library/prerelease/mac/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html#//apple_ref/doc/uid/TP40014216-CH6-ID61
Generic NSArrays can be realized by subclassing NSArray, and redefining all provided methods with more restrictive ones. For example,
- (id)objectAtIndex:(NSUInteger)index
would have to be redefined in
#interface NSStringArray : NSArray
as
- (NSString *)objectAtIndex:(NSUInteger)index
for an NSArray to contain only NSStrings.
The created subclass can be used as a drop-in replacement and brings many useful features: compiler warnings, property access, better code creation and -completion in Xcode. All these are compile-time features, there is no need to redefine the actual implementation - NSArray's methods can still be used.
It's possible to automate this and boil it down to only two statements, which brings it close to languages that support generics. I've created an automation with WMGenericCollection, where templates are provided as C Preprocessor Macros.
After importing the header file containing the macro, you can create a generic NSArray with two statements: one for the interface and one for the implementation. You only need to provide the data type you want to store and names for your subclasses. WMGenericCollection provides such templates for NSArray, NSDictionary and NSSet, as well as their mutable counterparts.
An example: List<int> could be realized by a custom class called NumberArray, which is created with the following statement:
WMGENERICARRAY_INTERFACE(NSNumber *, // type of the value class
// generated class names
NumberArray, MutableNumberArray)
Once you've created NumberArray, you can use it everywhere in your project. It lacks the syntax of <int>, but you can choose your own naming scheme to label these as classes as templates.
Take a look at:
https://github.com/tomersh/Objective-C-Generics
It appears to be a sort of poor-man's generics, by repurposing the protocol checking mechanism.
Now dreams come true - there are Generics in Objective-C since today (thanks, WWDC).
It's not a joke - on official page of Swift:
New syntax features let you write more expressive code while improving consistency across the language. The SDKs have employed new Objective-C features such as generics and nullability annotation to make Swift code even cleaner and safer. Here is just a sampling of Swift 2.0 enhancements.
And image that proofs this:
Just want to jump in here. I've written a blog post over here about Generics.
The thing I want to contribute is that Generics can be added to any class, not just the collection classes as Apple indicates.
I've successfully added then to a variety of classes as they work exactly the same as Apple's collections do. ie. compile time checking, code completion, enabling the removal of casts, etc.
Enjoy.
The Collections classes provided by Apple and GNUStep frameworks are semi-generic in that they assume that they are given objects, some that are sortable and some that respond to certain messages. For primitives like floats, ints, etc, all the C arrays structure is intact and can be used, and there are special wrapper objects for them for use in the general collection classes (eg NSNumber).
In addition, a Collection class may be sub-classed (or specifically modified via categories) to accept objects of any type, but you have to write all the type-handling code yourself.
Messages may be sent to any object but should return null if it is inappropriate for the object, or the message should be forwarded to an appropriate object. True type errors should be caught at compile-time, not at run-time. At run-time they should be handled or ignored.
Finally, Objc provides run-time reflection facilities to handle tricky cases and message response, specific type, and services can be checked on an object before it is sent a message or put into an inappropriate collection.
Beware that disparate libraries and frameworks adopt different conventions as to how their objects behave when sent messages they do not have code responses for, so RTFM. Other than toy programs and debugging builds, most programs should not have to crash unless they really screw up and try to write bad data to memory or disk, perform illegal operations (eg divide by zero, but you can catch that too), or access off-limits system resources.
The dynamism and run-time of Objective-C allows for things to fail gracefully and should be built in to your code.
(HINT) if yo are having trouble with genericity in your functions, try some specificity. Write the functions over with specific types and let the runtime select (thats why they are called selectors!) the appropriate member-function at run-time.
Example:
-(id) sort (id) obj; // too generic. catches all.
// better
-(id) sort: (EasilySortableCollection*) esc;
-(id) sort: (HardToSortCollection*) hsc;
...
[Sorter sort: MyEasyColl];
[Sorter sort: MyHardColl];
I try to dynamically call certain viewController/Feature depends on his Name.NSClassFromString
(that kind of idea was suggested by Facebook).
For Instance from my server I can define in IOS app which feature or viewController should be used.(or On/Off them)
I searched all over Stack but still cant find an elegant way to implement what I want
Class myclass = NSClassFromString(className);
id obj = [[myclass alloc] init];
will work.
But I would like to call my custom init.
Class myclass = NSClassFromString(className);
id obj = [[myclass alloc] initWithCostumInitializer:userInfo];
I cant find a proper way to do it. Of course every time I receive an error because initWithCostumInitializer is not recognised.So I need to make the decision in run time.I believe I missing something.
Tnx a lot.
First off, you shouldn't get a compile-time error about an unknown method if the headers for the possible classe(s) are imported into the .m file where this code is running. Because of exactly this sort of dynamism, ObjC should let you get away with calling fairly arbitrary methods on objects of type id.
But that's just a bandaid solution. Really, if you know that that custom initializer method is present, then it's not an arbitrary class, right? You have some idea what kind of object it is, or at least what kind of base class it derives from, otherwise you wouldn't know to call that method. So you could always:
id customObj = [((BaseViewController *)[myclass alloc]) initWithCustumInitializer:userInfo];
If your error is a runtime error about the receiver missing that selector, then you have a real problem, which is: why are you calling a named method on an object that might not be the kind of object that has that method? If that's what's happening, you'll need to look at the class first to figure out what kind of thing you're actually about to create, and then behave appropriately for the init.
As the ios's document says that we should creating a new object following
NSObject *newObject = [[NSObject alloc] init];
And never create a object like this
NSObject *someObject = [NSObject alloc];
[someObject init];
It says that the init may possible return the different than alloc,so I'm confused that why or in what case they return the different object?Thanks!
This behavior is allowed so that your class could produce a stand-in object for the one being created. You may want to do that for several reasons:
Object Caching - If you need to create and release the same objects often, for example, when you create wrapper objects for numeric values, you could store object instances for reuse, and return them when requested. If you make your objects immutable, you could save significant amounts of memory by sharing your objects.
Returning a subclass - There are multiple design reasons for doing this, for example, to implement hidden functionality that is compatible with the interface of the object being returned, such as copy-on-write.
Returning nil - You are allowed to do this to indicate failure of your init function.
Take as an example the huge number of initWith... methods of the NSString class. Some are very specialised, and would like to return a specialised object. alloc cannot know that. So [NSString alloc] returns a generic NSString object, and each initWith method can return some specialised object instead.
Because
NSObject *someObject = [NSObject alloc];
All alloc does is allocate memory for the object. At this point in time there is no actual NSObject type, just a region of memory. This doesn't have any direct consequence if you immediately call init but you might fail to realize the init wasn't called and attempt to use the object without initialization.
The other answer has an even better reason, you might not get the same object back from init.
This question already has answers here:
What is self in ObjC? When should i use it?
(6 answers)
Closed 9 years ago.
So, I just started learning Objective-C and I've come across this "self" thing. I've only ever used C, but I think it's used in java too maybe? Can someone explain? Here's an example:
- (IBAction)digitPressed:(UIButton *)sender
{
NSString *digit = [sender currentTitle];
UILabel *myDisplay = [self display]; //why this?
}
Why isn't it just this?
- (IBAction)digitPressed:(UIButton *)sender
{
NSString *digit = [sender currentTitle];
UILabel *myDisplay = display; //why not like this?
}
display is a UILabel *
[self display], or self.display, refers to a property / method (property is just a shortcut for get/set method anyway) if you have something like this in the .h file
#property (weak, nonatomic) UILabel* display;
or
-(UILabel*)display;
Just display, or self->display refers to an instance variable. This is valid when you have declared an instance var like this:
#implementation MyClass {
UILabel* display;
}
If you have declared the property display in the .h file and haven't changed its default, the corresponding instance var will be _display (note the underscore), in which case the following will be the same:
self.display and self->_display
In this case it's an objective C messaging thing. When you see the brackets it's doing this:
[Object Message]
Basically self is the object and display is the message your sending it. Sending it a message is like a method call in another language, but a little different under the hood. So something like this:
[self doSomethingCool];
in objective C would translate to something like this in another language:
this.doSomethingCool();
of course if running a method on another object you'll replace self with that object like:
[myObject doSomethingCool];
in a lot of languages you don't really need to have the "this" in front of your method call, it's implied that if you don't include it you're running the method in the object you're working with. I got burned pretty early on when I started with something similar. I had a call to a datalayer method where you could save an object and it would give you an integer back. When I was saving the object I didn't put the self in front of the method call and it was essentially generating a new object and saving it and I wasn't getting the right integer back.
Using "self" just explicitly tells it "I'm using THIS object". Same thing with properties, I always use "self.MyProperty" instead of "MyProperty" because I want to be explicit and make sure I'm using the MyProperty of the object I'm working in. It's semi rare for a defect like that to hit you, where you expect to be using a certain object and the environment thinks you're using another, but man when you run into one it's a head scratcher because everything looks right.
The word self refers to the current object, which is your view controller instance in this case, and combining it with a method name, which is display, means you are sending the message display to self which is the view controller. This will invoke the method display declared in your view controller instance.
You might declare the display method in your view controller, for example:
- (UILabel)display
{
//your display method implementation returning UILabel instance
}
For the second one, it means you are referring to display variable. For example:
UILabel *display = [[UILabel alloc] init];
display is not a UILabel * - it might be a property with that type, or a method which returns a value of that type, but these a rather different things.
You need to go an read something about object oriented programming. The self in Objective-C is the current object reference, other OO languages call it this - both Java and C++ use that name. Understanding objects and methods is fundamental to using any of these languages.
There's a very good explanation of this here:
http://useyourloaf.com/blog/2011/02/08/understanding-your-objective-c-self.html
The key section for your question is the section on Objective-C 2.0 dot syntax:
Objective-C Dot Syntax
The dot syntax was introduced with Objective-C 2.0 and generates a lot
of debate. A number of experienced and long time Cocoa programmers
recommend avoiding it completely. Others such as Chris Hanson have a
different view about when to use properties and dot notation.
Whichever side of the argument you fall I guess the main thing is to
be consistent.
Anyway the main thing to understand about the dot syntax is that the
following two statements are doing the same thing:
self.timestamp = [NSDate date];
[self setTimestamp:[NSDate date]];
The dot is just a shortcut for the more traditional Objective-C method
call. Any time you see a dot you can replace it with the equivalent
square bracket method call syntax. It is important to understand
however that this is not the same as writing the following:
timestamp = [NSDate date]; Without the self object and the dot we are
no longer sending an object a message but directly accessing the ivar
named timestamp. Since this bypasses the setter method we will
overwrite the timestamp ivar without first releasing the old NSDate
object. We will also not retain the new object that we are assigning.
Both of these situations are bad!
Keep in mind that the examples were written without using ARC, so there's a lot of references to memory management, retain, release etc. It is however useful to see these examples so that you have some idea of what ARC is doing in the background.
In your example, you are not referring to the actual display property with [self display] you are in fact referring to an instance method of the "self" object which in this case is your UIViewController.