A NSZombie of an odd type - ios

so i am getting a NSzombie and it says this
-[__NSArrayI _cfTypeID]: message sent to deallocated instance
Any idea what that is? assumably an array although i thought if it were an NS type it would say.

Yes — that'll be some type of array. Rather than being single classes, most of the foundation types are class clusters. So exactly how you initialise the array affects exactly which subclass of NSArray you get back.
The exact behaviour is undocumented and basically guaranteed to change over time but for example if you created an immutable array with less than a certain number of entries then the system might decide to return a single linked array and perform searches as simple linear searches. If you create one above the threshold then it might instead create an array that adds some sort of hierarchical logic for searching (or, more likely, contains the logic to create suitable hierarchical tables if the user starts trying to search the array).
Related lessons to learn:
never try to subclass a foundation class;
don't expect isMemberOfClass: to work properly;
don't even expect isKindOfClass: necessarily to be able to tell immutable from mutable versions of the foundation classes.
Apple needs a way to differentiate these classes and to flag them as private, so you end up with underscores and suffixes. In practice I think __NSArrayI is a vanilla immutable array.

Basically that means your NSArray object is already deallocated.
Something in Foundation.framework tried to access your NSArray's private method _cfTypeID and crashed.
And about question why there's _cfTypeID method in NSArray object. NSArray Core Foundation counterpart of CFArray. Two type's are interchangeable with "toll-free bridge".
So actually apple uses that method for internal uses.
If you want deeper understand of this. You can visit http://code.google.com/p/cocotron/source/browse/Foundation/NSArray/NSArray.m and this is Cocotron's implementation of NSArray. It is not same with the apple's implementation but still implementations are similar.

Related

How "id" type understands the receiver of method without casting?

After merging master to my working branch I got compiler error on the line, which wasn't be changed. The error looks like
id test;
[test count];
Multiple methods named 'count' found with mismatched result.
At first it looks clear, because compiler doesn't know which concrete type the "test" variable is. But I don't understand why it worked before.
If I create a new file this line works, assuming that is a NSArray's method. Why compiler doesn't show error in this case?
While showing error message, there is several possible receivers of count method are shown. (NSArray, NSDictionary, NSSet) Does it search all classes that can receive that message and show error if there are multiple?
I noticed that error occurs when I import "-Swift.h" file. How it depends?
Compiler doesn't cast or check your id type. It just provides you all possible selectors. You said that this issue connected with importing "-Swift.h" file. In this case check you Swift code, probably you have count function visible for Objective C which returns something else than Int.
Also, you can check the issue in Issue navigator, select it and it will show all count calls visible in Objective C. Check them all, most of them will return NSUInteger, but there should be one that returns something else, for example:
SWIFT_CLASS("_TtC3dev19YourClass")
#interface YourClass : NSObject
- (int32_t)count SWIFT_WARN_UNUSED_RESULT;
#end
Objective-C doesn't need to know the type of the receiver. At run-time, all objects are just id, and everything is dynamically dispatched. So any message can be sent to any object, no matter its type. (At run-time, objects are free to decide what to do with messages they don't understand. The most common thing to do is raise an exception and crash, but there are many kinds of objects that can handle arbitrary messages that don't map directly to method calls.)
There is a couple of technical details, however, that complicate this.
The ABI (application binary interface) defines different mechanisms for returning certain primitive types. As long as the value is "a word-sized integer," then it doesn't matter (this includes things like NSInteger and all pointers, which means by extension all objects). But on some processors, floats are returned in different registers than integers, and structs (like CGRect) might be returned in a variety of ways depending on their size. In order to write the necessary assembly language, the compiler has to know what kind of return value it will be.
ARC has added additional wrinkles that require that the compiler know a more about the type of the parameters (specifically whether they're objects or primitives), and whether there are any memory-management attributes that have to be considered.
The compiler doesn't really care what "real" type test is, as long as it can figure out the types and attributes of -count. So when dealing with an id value, it looks through every known selector it can see (i.e. every one defined in an included header or the current .m). It's fine if there are many of them on different classes, as long as they all agree. But if it can't find the selector at all, or if some of the interfaces disagree, then it can't compile the line of code.
As lobstah notes, you likely have a type somewhere in your Swift code that has an #objc method called count() or an #objc property named count that returns something other than Int (which maps to NSInteger, and so match the usual signature of -count). You'll need to fix that method, or you'll need to hide it from ObjC (for example, by adding #nonobjc).
Or much better: get rid of the id, and use its actual type. id is generally a bad idea in Cocoa, and is especially a bad idea if you're calling methods on it, since the compiler can't check that the object will respond and you may crash.

Why isKindOfClass and isMemberOfClass works badly with NSString and NSMutableString?

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.

Is the use of id type in method a good practice?

I am creating a set of API and some users have suggested that I use id type for a particular method that can accept custom object (defined by the API) or string instead of creating two versions. Is the use of id type in method a good or acceptable practice? Does Apple do it with their any of their API?
That would be very poor practice. If you're creating an API you need to retain full control, and allowing users to pass any object to your method at which point you would have to cast it to that object or string you mentioned could be fatal depending on what's passed. Creating two methods with different parameters is not only okay, but follows the tenets of polymorphism to the T.
Accepting id is not in itself good or bad practice. How much manual procedural if/then/else/if/then/else nonsense will you acquire? If quite a lot then something is wrong.
Put another way: if the conditional logic related to different kinds of object ends up being implicit, via the Objective-C dispatch mechanisms, then the design is good. If you end up impliedly reimplementing dynamic dispatch then you've gone completely wrong.
Apple does it frequently. Just off the top of my head there are:
as per Nikolai's comment, all the collection types: set, dictionary, array, etc.
anything that takes %# as a format specifier: NSLog, certain methods on NSString, etc.
anything that still uses an informal protocol.
anything in or semi-close to the runtime like key-value coding.
archiving and the user defaults.
anywhere that storage is offered for your own use — the hardy userInfo on NSTimer and the rest.
anywhere that target/action is used — all UIControls, the notification centre, etc.
As per my comment, suppose your custom class had this method:
- (NSData *)dataUsingEncoding:(NSStringEncoding)encoding
And suppose it were the only method being called by whomever is being passed either a string or your custom object. Then id would be the right choice, since you'd have in effect implemented an informal protocol, and the thing being passed an object genuinely doesn't care whether it's a string or not. The only contractual requirement is the informal protocol and the protocol is informal i.e. has no footprint on the type syntax.
Conversely, suppose your custom class had no methods in common with NSString and your code just looked like:
- (void)myMethod:(id)object
{
if([object isKindOfClass:[NSString class]])
[self myMethodOnString:object];
else
[self myMethodOnCustomClass:object];
}
Then id would be inappropriate. You're just obscuring what the method does and implicitly reproducing work that's built into the runtime anyway.

Creating a Model Object with an NSDictionary

This is something I have been playing with, and have yet to make my mind up about.
When querying a database, it is extremely common that you will use the data in the response to create custom model objects. Let's use 'Book' as an example.
I have received JSON describing multiple Book objects. I parse the JSON into an NSArray of NSDictionarys. I now have a few options:
Make all properties on Book mutable (I hate this option). You could then have a BookManager class with takes an NSArray of NSDictionarys and maps the data in the dictionary to the correct properties.
Add an initialiser to the Book object which accepts the important details.
Example:
- (instancetype)initWithTitle:(NSString *)title author:(NSString *)author publishDate:(NSDate *)publishDate;
The aforementioned BookManager class could then take the NSDictionarys as before, but create the Book objects with this initialiser. This is nice, because you could then make all of the public facing properties on Book readonly. However, it is very limited, and if (as is often the case) there are a lot of properties on the model, this is not feasible.
Add an initialiser to Book which accepts the NSDictionary representation of itself. I dislike this approach in one way because I feel the responsibility is not the model's to create itself from a dictionary. I prefer the idea of a manager class mapping the dictionary to the model. However, I do like the fact that it means that all properties can be readonly.
There is no doubt in my mind I am missing other options, and if you are aware of them, please point them out. The aim of this question is to finally determine the best way to approach this scenario.
I regularly use an init method with the important arguments, but yes, it becomes very unwieldily when the number of arguments reach double digits and/or several of the arguments can be nil. The longest such method I have seen in the iOS SDK is CLLocation's
- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate
altitude:(CLLocationDistance)altitude
horizontalAccuracy:(CLLocationAccuracy)hAccuracy
verticalAccuracy:(CLLocationAccuracy)vAccuracy
course:(CLLocationDirection)course
speed:(CLLocationSpeed)speed
timestamp:(NSDate *)timestamp
Regarding your last option, adding an initWithDictionary: method to Book could be expanded to also include a class-level method for creating instances of Book from an NSDictionary.
+ (instancetype)bookWithDictionary:(NSDictionary *)dictionary
And optionally a convenient way to get a dictionary representation from a Book instance.
- (NSDictionary *)dictionaryRepresentation
If you search the iOS documentation for "withDictionary" and "dictionaryRepresentation" you will see a few places where this is used. In other SDKs, you will sometimes see the method named as someObjectFromDictionary:
I think u can do this using JSONModel
see this
http://code.tutsplus.com/tutorials/getting-started-with-jsonmodel--cms-19840
https://github.com/icanzilb/JSONModel

Objective-C iOS app not storing data in array of objects

this is a very hard question to ask because I don't want to flood you with all of my code, being that most of it is not pertinent to the problem. So I won't be to surprised if this goes unanswered. Although, it could be something hella simple that I am missing haha. Here it goes:
So my app is storing an array via [encoder] in my appDelegate. The app is full of objects that are creates in a separate NSObject class. Think of it this way for examples sake:
I have my main viewController class. And in appDelegate I define/encode an array of objects.
Now in my main, I fill the array with 10 "cars". My car class has variables such as color, make, model, etc.. Now when I save and relaunch the app, the array that I have saved is now an array containing 10 elements, but it seems to have forgotten all of the variables for each instance of the car class.
When I relaunch the app, If I call NSLog(#"%#",array in appDelegate); It prints 10 lines that look a lot like this:
""
So I know the array is being stored with 10 elements, and 10 elements are saved, but like i said, all of the variables are gone.
Note: On the first run of the app, and the array is being filled for the first time, I can access all the variables perfectly, and nothing is wrong.
Thank you for any help that I can get!!
We need to see the code for your implementation of initWithCoder and encodeWithCoder on the "car" class. If you haven't implemented them, that's your problem.
What is probably happening currently is that only the superclass implementation of these methods is being invoked. This means the correct class will be recreated but no data will be saved or restored.
NSCoding protocol reference doc.
Your main class as well as all the objects you put into the array all need to conform to NSCoding. If the objects in the array aren't NSCoding compliant, they won't get coded automatically.

Resources