I've run into some problems using NSManagedObjectID and it changing depending on it's saved state.
As such I've decided to use my own UniqeIDs as recommended in the docs and by others. I've seen many examples here on Stack Overflow and on other places where it's a simple matter of storing a NSUUID string value in a core data field.
However, this isn't quite enough for what I want. One of the useful things about NSManagedObjectID is that it is always the same object and can be compared by pointer, so you can post notifications around using the NSManagedObjectID as their object, anything that requires information about the entity can register for notification based on the NSManagedObjectID without writing additional code to check if the notification is indeed the one we're looking for.
However, would that be still be true if an NSString is passed around instead of the NSManagedObjectID? We're always supposed to use isEqualTo for NSString comparison, even if it might be the same object. I feel like using an NSString as an object for a notification is a bit of a no no.
In my case, it's pretty much guaranteed be the same object, unless objective c messes around with NSString behind the scenes. the uniqueID is generated once on insertion of an object, and would be passed around unaltered as required, and I simply want to replace all calls where I use NSManagedObjectID with something I can drop in with minimal changes.
A CFUUID would seem ideal, as they can be guaranteed to share pointer values, however CFUuidRef is not an objective-c object, so can't be used for notifications among other things. An NSUUID seems next to best apart from the caveat in the documentation that says they aren't guaranteed to be the same object. But if my NSUUID is created, stored and retrieved on a single object, could we guarantee the passed around NSUUID to be the same object throughout the application? If so, couldn't we say the same thing about an NSString? Even if we could, I'd be happier just going with NSUUID.
I can't pass around the Entity directly, as I'm using the notification to post information between separate threads. Even though I only ever modify the entities on the main thread, and entities can be accessed for readonly across threads, I've had many problems in the past, that all went away once I implemented a system based on using just the NSManagedObjectID.
Maybe I got you wrong, but why not passing around instances of NSUUID (if you do not want to use instances of NSString) and comparing them on equality?
#interface NSUUID(Equality)
- (BOOL)isEqualToUUID:(NSUUID*)other;
#end
#implementation NSUUID(Equality)
- (BOOL)isEqualToUUID:(NSUUID*)other
{
return [self.UUIDString isEqualToString:other.UUIDString];
}
// Only for completness
- (BOOL)isEqual:(id)other
{
if( [other isKindOfClass:[NSUUID class]] )
{
return [self isEqualToUUID:other];
}
return NO;
}
#end
BTW: The same reasons that make you feel badly using instances of NSString as notification object does not apply to instances of NSUUID?
BTW 2: Handling CF-objects in ARC code is not that difficult.
Related
I'm new to objective C and there's something odd that I don't understand.
How can I even call a NSString method on a NSDate object? For example:
NSString* ptr = [[NSString alloc] init];
[ptr uppercaseString];
NSDate* dPtr = [[NSDate alloc] init];
[dPtr uppercaseString];
id temp;
[temp uppercaseString];
Well, I do get that id can point to anything but how does it even know of the existence of the uppercaseString method without casting or something?
I'm have a C++ and Java background where I didn't notice anything like this before.
I'd love to get an explanation.
Unlike Java and C++, Objective-C has weak typing and late binding, which explains that you don't have to do a cast.
This is one of big dividing lines in object-oriented programming: Whether the language uses strong typing, so a variable can only hold references (or pointers) to objects of a given class and its subclasses, or if it can hold anything. If a variable can hold any object, the exact method implementation then has to be resolved at runtime when a message is received.
Objective-C got the philosophy of late binding from Smalltalk (see smalltalk), but is moving towards a more and more strictly typed language (formal protocols, use of the id type discouraged, etc.). The basics remain the same, however.
This is also one of the reasons, contrary to C++, Objective-C needs a runtime in order to run on your machine. Something has to take care of those method lookups.
Because the check for the existence of the method is not made right before the call but while trying to find the method. What actually happens (simplified a lot is)
[obj methodCall];
=> replaced => objc_send(obj, #"methodCall")
Inside the C function objc_send The call itself is resolved and made
If(obj.respondsTo(methodCall) Then obj.methodCall();
Objective-C methods are not the same as Java or C++ methods. They are messages, and they exist independently of any class or object. When you write (taken from CocoaDevCentral) in Photo.h:
#import <Cocoa/Cocoa.h>
#interface Photo : NSObject {
NSString* caption;
NSString* photographer;
}
- caption;
- photographer;
#end
you are saying that the Photo class has a caption and a photographer object, and that it will respond to the messages caption and photographer. That was the old pre-properties way of writing code for those two items.
You will write code in Photo.m giving the implementation of the two messages, so that a Photo can respond to them. But nothing stops you from sending caption to any object. It's like the old Far Side cartoon about what we say to dogs and what they hear. Any errors occur at runtime.
So, what happens when you send a message to an object that it does not know how to respond to? If you have not done anything special,
The runtime system packages the message into a thing of type SEL.
It sends the doesNotRecognizeSelector: message to the object with that selector.
The object inherits from NSObject an implementation that raises a NSInvalidArgumentException.
However, there are a few opportunities before that to intervene by overriding a method:
+ (BOOL) resolveInstanceMethod:(SEL)aSEL
This lets you install an implementation at runtime.
- (id)forwardingTargetForSelector:(SEL)aSelector
This lets you nominate another object to accept the message.
- (void)forwardInvocation:(NSInvocation *)anInvocation
This lets you handle the message any way you want.
Before Objective-C gained blocks, there were a number of libraries that used forwarding for functional programming. Suppose you have an NSArray of Accounts that all understand the balance message. Suppose then you want to collect the balances of all the accounts in another NSArray. Instead of looping, the library provided a category for NSArray with a collect message, and you would write:
NSArray *accounts = ...;
NSArray *balances = [[accounts collect] balance];
The result of [accounts collect] does not have an implementation for the balance message; how could it? collect is provided by the library. Instead, it has a forwardInvocation: implementation that sends the balance message to all the members of accounts, and creates a new NSArray from them. One might use blocks and enumerateObjectsUsingBlock: these days, but that was a quite succinct and powerful technique.
Others have provided the answer - late binding, the method is looked up on the object at runtime without concern for the type of the object - if it has an appropriate method it is called.
However your call above [dPtr uppercaseString] should produce an error from Xcode. While the compiler will perform a lot of checks and refuse to compiler some programs (such as the above) that is really all the type-checking you get and it can be easily by-passed (e.g. [(id)dPtr uppercaseString] will remove the error and let you code run - when it will promptly fault due to no such method on NSDate).
Essentially the types are comments, if you use them properly you code should be type-correct, but there is no requirement for type-correctness for your code to compile.
I have seen some iOS developpers using code like this :
- (void)setupWebView:(UIWebView**)aWebView {
UIWebView *webview = [[UIWebView alloc] init];
.....
if (*aWebView) {
[*aWebView release];
}
*aWebView = webview;
}
Do you know what'is this mean and why we use this ? thanks
- (void)setupWebView:(UIWebView**)aWebView {
That is awful. You should never have a method that returns void, but sets an argument by reference unless:
• there are multiple arguments set
• the method is prefixed with get
That method should simply return the created instance directly. And this just makes it worse -- is flat out wrong:
if (*aWebView) {
[*aWebView release];
}
*aWebView = webview;
it breaks encapsulation; what if the caller passed a reference to an iVar slot. Now you have the callee managing the callers memory which is both horrible practice and quite likely crashy (in the face of concurrency, for example).
it'll crash if aWebView is NULL; crash on the assignment, specifically.
if aWebView refers to an iVar slot, it bypasses any possible property use (a different way of breaking encapsulation).
It is a method to initialize a pointer. The first line allocates the object. The if statement makes sure that the passed in pointer-to-a-pointer is not already allocated, if it is it releases it. then it sets the referenced pointer to the newly allocated object.
The answer by #bbum is probably correct, but leaves out one aspect to the question that I see there. There are many examples in Foundation which use pointer-pointers in the method signature, so you can say it is a common pattern. And those are probably not a beginners mistake.
Most of these examples are similar in that they fall into one category: the API tries to avoid the usages of exceptions, and instead use NSError for failures. But because the return value is used for a BOOL that signals success, an NSError pointer-pointer is used as output parameter. Only in the probably rare error case an NSError object is created, which can contain error code and error descriptions, and localized descriptions and possibly even more information (like an array of multiple errors in the case of bulk operations). So the main success case is efficient, and the error case has some power to communicate what went wrong, without resorting to exceptions. That is the justification behind these signatures as I understand it.
You can find examples of this usage in both NSFileManager and NSManagedObjectContext.
One might be tempted to use pointer-pointers in other cases where you want multiple return values and an array does not make sense (e.g. because the values are not of same type), but as #bbum said, it is likely better to look hard for alternatives.
I have a number of functions similar to the following:
+ (NSArray *)arrayOfSomething
{
NSMutableArray *array = [NSMutableArray array];
// Add objects to the array
return [[array copy] autorelease];
}
My question is about the last line of this method: is it better to return the mutable object and avoid a copy operation, or to return an immutable copy? Are there any good reasons to avoid returning a mutable object where one is not expected?
(I know that it is legal to return a NSMutableArray since it is a subclass of NSArray. My question is whether or not this is a good idea.)
This is a complex topic. I think it's best to refer you to Apple's guidelines on object mutability.
Apple has this to say on the subject of using introspection to determine a returned object's mutability:
To determine whether it can change a received object, the receiver must rely on the formal type of the return value. If it receives, for instance, 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
(my emphasis)
The article goes on to give several very good reasons why you should not use introspection on a returned object to determine if you can mutate it e.g.
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. Afterwards 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.
and
You ask NSView for its subviews (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 NSView’s internal data structures.
Given the above, it is perfectly acceptable for you to return the mutable array in your example (provided of course, you never mutate it yourself after having returned it, because then you would be breaking the contract).
Having said that, almost nobody has read that section of the Cocoa Objects Guide, so defensive programming would call for you to make an immutable copy and return that unless performance profiling shows that it is a problem to do that.
Short Answer: Don't do it
Long Answer: It depends. If the array is getting changed while being used by someone who expects it be static, you can cause some baffling errors that would be a pain to track down. It would be better to just do the copy/autorelease like you've done and only come back and revisit the return type of that method if it turns out that there is a significant performance hit.
In response to the comments, I think it's unlikely that returning a mutable array would cause any trouble, but, if it does cause trouble, it could be difficult to track down exactly what the issue is. If making a copy of the mutable array turns out to be a big performance hit, it will be very easy to determine what's causing the problem. You have a choice between two very unlikely issues, one that's easy to solve, one that's very difficult.
I tried to figure out this code referencing: Cocoa: Dictionary with enum keys?
+ (NSValue*)valueWithReference:(id)target
{
return [NSValue valueWithBytes:&target objCType:#encode(id*)];
}
And,
[table setObject:anObject forKey:[NSValue valueWithReference:keyObject]];
But it feels something not good. Any recommendations?
You're absolutely right it's not good.
For one, you're encoding the wrong type (it should be #encode(id), not #encode(id*)), but in most cases this shouldn't cause a big problem.
The bigger problem is that this completely ignores memory management. The object won't be retained or copied. If some other code releases it, it could just disappear, and then your dictionary key will be a boxed pointer to garbage or even a completely different object. This is basically the world's most advanced dangling pointer.
You have two good options:
You could either add NSCopying to the class or create a copyable subclass.
This option will only work for objects that can meaningfully be copied. This is most classes, but not necessarily all (e.g. it might be bad to have multiple objects representing the same input stream)
Implementing copying can be a pain even for classes where it makes sense — not difficult, per se, but kind of annoying
You could instead create the dictionary with the CFDictionary API. Since Core Foundation types don't have a generic copy function, CFDictionary just retains its keys by default (though you can customize its behavior however you like). But CFDictionary is also toll-free bridged with NSDictionary, which means that you can just cast a CFDictionaryRef to an NSDictionary* (or NSMutableDictionary*) and then treat it like any other NSDictionary.
This means that the object you're using as a key must not change (at least not in a way that affects its hash value) while it's in the dictionary — ensuring this doesn't happen is why NSDictionary normally wants to copy its keys
For the later reference.
Now I know that there are some more options.
Override methods in NSCopying protocol, and return the self instead of copying itself. (you should retain it if you are not using ARC) Also you ensure the object to always return same value for -hash method.
Make a copyable simple container class holds strong reference to the original key object. The container is copyable but, it just passes original key when it being copied. Override equality/hash methods also to match semantics. Even just an instance of NSArray contains only the key object works well.
Method #1 looks pretty safe but actually I'm not sure that's safe. Because I don't know internal behavior of NSDictionary. So I usually use #2 way which is completely safe in Cocoa convention.
Update
Now we Have NSHashTable and NSMapTable also in iOS since version 6.0.
I'm not 100% sure about the correctness of this solution, but I'm posting it just in case.
If you do not want to use a CFDictionary, maybe you could use this simple category:
#implementation NSMutableDictionary(NonCopyableKeys)
- (void)setObject:(id)anObject forNonCopyableKey:(id)aKey {
[self setObject:anObject forKey:[NSValue valueWithPointer:aKey]];
}
- (id)objectForNonCopyableKey:(id)aKey {
return [self objectForKey:[NSValue valueWithPointer:aKey]];
}
- (void)removeObjectForNonCopyableKey:(id)aKey {
[self removeObjectForKey:[NSValue valueWithPointer:aKey]];
}
#end
This is a generalization of a similar method I saw online (can't find the original source) for using an NSMutableDictionary that can store objects with UITouch keys.
The same restriction as in Chuck's answer applies: the object you're using as a key must not change in a way that affects its hash value and must not be freed while it's in the dictionary .
Also make sure you don't mix -(void)setObject:(id)anObject forNonCopyableKey:(id)aKey and - (id)objectForKey:(id)aKey methods, as it won't work (the latter will return nil).
This seems to work fine, but there might be some unwanted side effects that I am not thinking of. If anybody finds out that this solution has any additional problems or caveats, please comment.
I'm creating a base class that has an isDirty flag. It is set any time one of its properties changes, but since it's a base class, it doesn't know what its properties are. So basically, on every subclass, I have to override every - set: method to something like this:
- (id) setName:(NSString *)value {
if ([name isEqualToString:value]) {
return;
}
[name autorelease];
name = [value retain];
isDirty = YES; //Here's the important bit
}
Almost every line of that is what the automatically-synthesized setter would do. Is there any way I can override what #synthesize actually creates?
There are other options I have come up with, but they all seem like they would be much slower at runtime than this method. I've thought of things like adding an object to observe its own property changes, or creating a generic function to do all that and just pass in the address to the iVar and the new value, but that still requires overriding the setter.
Any ideas? If it makes a difference, it's for an iPhone app.
Several issues here:
(1) If you are concerned about setter performance, you shouldn't be using -isEqualToString: in your setter. Do a pointer compare instead because that is all that matters in this context.
(2) If you have an NSString attribute, you should be copying on set. Copy is free for immutable strings and will save your bacon for mutable strings (by preventing the caller from mutating the string out from under you).
(3) Again with performance; you checked for equality, but then use autorelease. That incurs unnecessary overhead.
(4) * they all seem like they would be much slower at runtime* indicates that you haven't actually tried it, haven't identified a performance problem, and are prematurely optimizing your code. Given (1) and (3), there is likely much more easily addressed performance issues.
My suggestions:
(1) Use #synthesize. It will generate correct and fast code, addressing (1) and (3).
(2) Use KVO or one of the other mechanisms. Until you identify a performance problem through instrumentation and quantification, you don't have a performance problem.
(3) Consider using CoreData (unless, of course, you are targeting OS 2.x). The example code is from something that is obviously a model object. If your code is nicely factored into model/view/controller, using CoreData at the model layer can both simplify your application and CoreData does a wonderful job of change tracking.
There's no way I know of that enables you to override what #synthesize does.
At the end of the day, it's used for creating basic accessor methods - ie. those that don't have specific behaviour.
Maybe you should look into Key Value Coding and Key Value Observing?
There isn't.
What you want to achieve is only possible by digging deep into the Objective-C runtime or by using proxy objects.
Why don't you have a look at KVO again?
If you write your own accessor method(s) #synthesize respects that. #synthesize gives precedence to accessors you write on your own. Just provide the accessor you like and #synthesize will be ignored on that one. For example you could implement an accessor that creates the property only in case it isn't already there.
Example:
#synthesize standardUserDefaults;
- (NSUserDefaults *)standardUserDefaults {
NSLog(#"standardUserDefaults");
if (!standardUserDefaults) {
NSLog(#"standardUserDefaults new");
self.standardUserDefaults = [NSUserDefaults standardUserDefaults];
}
return standardUserDefaults;
}
Here the "setter" is synthesized while the "getter" is not.