KVO differentiating between willChangeValueForKey and didChangeValueForKey - are both necessary? - ios

In line with Apple's own recommendations, when setting KVC/KVO compliant accessors manually, one should include BOTH KVO methods willChange and didChange. This is what I have done in all my manual accessor methods.
However, observeValueForKeyPath:ofObject:change:context gets called for each half of the KVC methods (will and did) with exactly the same dictionary contents.
When registering an observer using the option: NSKeyValueObservingOptionPrior the observer still gets called twice - once for each half - and, again, with identically the same dictionary contents, save only the difference that the key 'notificationIsPrior' is included in the dictionary.
Now, when KVO is used to alter 'CPU-expensive' attributes - like changing a colour or redrawing a large and elaborate design, it makes sense only to act on the 'didChange' and ignore (or at least separate out) the 'willChange'. In the past, I have achieved this by converting the key string into an enum list element that returns a left-shifted '1' and used this digit to set a flag in a 32 or 64 bit integer on receipt of the first call and when the flag is reset on the second, I execute the CPU-intensive operation(s).
However, it strikes me that this is a non-trivial overhead to implement for every case. Does anyone have any other 'preferred' way of differentiating between the callback for 'willChange' and that for 'didChange' without allowing the same processing to be done twice?
I have scoured Apple's own documentation and this help group copiously for alteranatives but Apple's own doc doesn't actually go in to much detail on the subject and several people in this group have also wrestled with a similiar concern. In neither instance has a definitive solution been offered. If anyone knows of a better way - other than dodging the 'willChange' using alternating flags - I'd be very grateful. (Why couldn't Apple just include a 'phase' key in the change dictionary???)

I think this is what you were getting at in the comments, but for the benefit of future visitors:
If you want to tell whether a callback is "before" or "after" you can look for the NSKeyValueChangeNotificationIsPriorKey key in the change dictionary. If it's a prior notification, this key will be equal to [NSNumber numberWithBool: YES] (incidentally the dictionary will also not contain a value for the NSKeyValueChangeNewKey) The presence/value of NSKeyValueChangeNotificationIsPriorKey is authoritative, so if you're seeing it when you're not expecting to, you might be getting double callbacks.
If you're getting double callbacks it may be, as it sounds like it was in VectorVictors case, that the runtime is firing them AND you're firing them. If you plan to call will/didChangeValueForKey: to manage your KVO notifications manually, (and you don't want double notifications,) you should implement the following class method:
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey {
BOOL automatic = NO;
if ([theKey isEqualToString:#"propertyYourePlanningToManageYourself"]) {
automatic = NO;
} else {
automatic=[super automaticallyNotifiesObserversForKey:theKey];
}
return automatic;
}
This is described in detail in Apple's Key-Value Observing Programming Guide.

Related

What happens if the `NEPacketTunnelflow` method `readPacketsWithCompletionHandler` is called multiple times?

When calling the method
- (void)readPacketsWithCompletionHandler:(void (^)(
NSArray<NSData *> *packets, NSArray<NSNumber *> *protocols))completionHandler;
the completionHandler is either called directly, in case packets are available at call time, or it is called at a later tim when packets become available.
Yet what is nowhere documented is: What happens if I call this method again before the prior set completionHandler has ever been called?
Will the new handler replace the prior set one and the prior set one won't get called at all anymore?
Are both handler scheduled and called as data arrives? And if so, will they be called in the order I passed them, in reverse order, or in random order?
Has anyone any insights on how that method is implemented?
Of course, I can make a demo project, create a test setup, and see what results I get through testing but that is very time consuming and not necessarily reliable. The problem with unspecified behavior is that it may change at will without letting anyone know. This method may behave differently on macOS and iOS, it may behave differently with every new OS release, or depending on the day of the week.
Or does the fact that nothing is documented is by intention? Do I have to interpret that as: You may call this method once and after your callback was executed, you may call it again with the same or a new callback. Everything else is undefined behavior and you cannot and should not rely on any specific behavior if use that API in a different manner.
As nobody has replied so far, I tried my best to figure it out myself. As testing is not good enough for me, here is what I did:
First I extracted the NetworkExtension framework binary from the dyld cache of macOS Big Sur using this utility.
Then I ran otool -Vt over the resulting binary file to get a disassembler dump of the binary.
My assembly skills are a bit rusty but from what I see the completionHandler is stored in a property named packetHandler, replacing any previous stored value there. Also a callback is created in that method and stored on an object obtained by calling the method interface.
When looking at the code of this created callback, it obtains the value of the packetHandler property and sets it to NULL after the value was obtained. Then it creates NSData and NSNumber objects, adds those to NSArray objects and calls the obtained handler with those arrays.
So it seems that calling the method again just replaces the previous completionHandler which is never be called in that case. So you must not rely that a scheduled handler will eventually be called at some time in the future if the tunnel is not teared down if the possibility exists that your code might replace it. Also calling the method multiple times to schedule multiple callbacks has no effect as as only the last one will be kept and eventually be called.

Can I implement a property setter in such a way that it calls another method generically to perform the set?

Consider the below setters:
- (void)setWinterStatus:(NSString *)status
{
NSLog(#"Variable update called");
if (_status != status)
{
[_status release];
_status = [status retain];
NSLog(#"Variable actually updated");
}
}
- (void)setCharacterState:(EnumCharacterState)state
{
NSLog(#"Variable update called");
if (_state != state)
{
_state = state;
NSLog(#"Variable actually updated");
}
}
Notice the methods are similar - it logs a generic message, checks if it's actually changing, effects the change, and logs if it does so. If I had enough such methods, I might want to write a wrapper, so that I could simply write:
- (void)setCharacterState:(EnumCharacterState)state
{
[setValue:#(state) forSelector:#selector(state)];
}
But I'm not sure if this is possible. I can't use KVO as it seems the KVO code added by default actually call's the setter, so doing so results in endless recursion. I don't know how to get the instance variable from #selector(state), nor check whether it needs release/retain. Any way to do this?
One note: the object type's base class has to remain NSObject; I can't use NSManagedObject as a base and handle my own KVO.
Edit:
So there apparently is a way using the runtime c functions (see accepted answer); seems like it could take some time to get right, but I found another solution in the interim. I register myself an an observer for all the methods I want to 'wrap', observing NSKeyValueObservingOptionNew, NSKeyValueObservingOptionOld, and NSKeyValueObservingOptionPrior. Then in the prior handler, I NSLog(#"Variable update called"), and in the update handler, I NSLog(#"Variable actually updated"). This seems to be working out well :)
Short Answer: Yes, but don't.
Long Answer:
Assuming you want to do this for educational reasons (rather than just have the compiler create the setter for you, the default in recent compilers) it is possible, but it is non-trivial.
You've noticed one difference - whether you need to retain/release (assuming MRC) - but there are more. For example, consider the simple line:
_state = state;
What does it do? Copy a byte? Two bytes? Eight bytes? The code might look the same in different setters but it compiles to different machine code.
And then there are copy and weak attributes on properties to consider...
Still considering doing this?
You'll need to be comfortable with what void ** means, copying data of variable length via pointers, etc. Then take a look at object_setInstanceVariable, property_getAttributes etc. - these are all C functions, you'll find them in Objective-C Runtime Reference.
From that you'll find you need to know about type encodings (which will help you with how many bytes to copy around), and more...
Have fun!
HTH

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.

UILexicon in Objective-C

How do you use UILexicon in Objective-C? I find the documentation Apple provides is extremely unhelpful.
What does it do? Does it return a dictionary or proper spellings of words? Or do I provide a word like "hellllo" and it matches it with the proper spelling "Hello" and returns that as a string?
Any help would be appreciated.
requestSupplementaryLexiconWithCompletion:
Here's my error report, but obviously I'll have errors because I'm completely guessing how to use the function, no clue what goes inside the block statement (because the docs (at the time) don't say! (Beta 4 docs)) Hahahah!
I've never used this feature, but a quick web search for "UILexicon" landed me in Apple's documentation; reading and following links from there filled in the picture pretty quick.
App Extension Programming Guide has a quick explanation of what lexicons are for:
Every custom keyboard (independent of the value of its RequestsOpenAccess key) has access to a basic autocorrection lexicon through the UILexicon class. Make use of this class, along with a lexicon of your own design, to provide suggestions and autocorrections as users are entering text.
Clicking the UILexicon link on that page took me to the reference doc for that class, which explains that it's a read-only list of Apple-provided term pairs. Each of its entries is a UILexiconEntry object -- the docs for that class say it provides a userInput (what the user typed, e.g. "ipad") and a documentText (what to substitute for it, e.g. "iPad"). Since those classes are read-only, it follows that they're probably not a way for you to provide your own autocorrection pairs -- as stated in the docs, they're for supplementing whatever autocorrection system you implement.
At this point, I don't even have to look at the doc for requestSupplementaryLexiconWithCompletion: to get a good idea how to use it: just the declaration tells me:
It's a method on UIInputViewController, the class I'd have to subclass to create a custom keyboard. Somewhere in that subclass I should probably call it on self.
Its return type is void, so I can't get a lexicon by assigning the result of a requestSupplementaryLexiconWithCompletion call to to a variable.
It calls the block I provide, passing me a UILexicon object as a parameter to that block.
It's got words like "request" and "completionHander" in it, so it'll probably do something asynchronous that takes awhile, and call that block when it's done.
So, I'm guessing that if I were writing a custom keyboard, I'd call this method early on (in viewDidLoad, perhaps) and stash the UILexicon it provides so I can refer to it later when the user is typing. Something like this:
#property UILexicon *lexicon;
- (void)viewDidLoad {
[super viewDidLoad];
[self requestSupplementaryLexiconWithCompletion:^(UILexicon *lexicon){
self.lexicon = lexicon;
}];
}
Because it's unclear how long requestSupplementaryLexiconWithCompletion will take to complete, any place where I'm using self.lexicon I should check to see if it's nil.
Back in the App Extension Programming Guide, it lists "Autocorrection and suggestion" under "Keyboard Features That iOS Users Expect", right before saying:
You can decide whether or not to implement such features; there is no dedicated API for any of the features just listed
So it sounds like autocorrection is something you have to do yourself, with your own UI that's part of the view presented by your UIInputViewController subclass. The API Quick Start for Custom Keyboards section in the programming guide seems to hint at how you'd do that: use documentContextBeforeInput to see what the user has recently typed, deleteBackward to get rid of it, and insertText: to insert a correction.

Why do we needed category when we can use a subclass? and Why we needed blocks when we can use functions?

These two questions are quite common when we search it but yet I need to get a satisfying answer about both.When ever we search a difference between say subclass and a category we actually get definition of both not the difference.I went to an interview to a very good MNC working on iOS and I was encountered with these two questions and I gave almost all the answers I have read here but the interviewer was not satisfied.He stuck to his questions and was that-
Why do we needed category when we can use a subclass?
Why we needed blocks when we can use functions?
So please explain me what specific qualities blocks and category add in objective C that their counter part can't do.
First...
Just reading the documentation "Subclassing Notes" for NSString shows why creating categories is sometimes better than subclassing.
If you wanted to add a function -(void)reverseString (for instance) to NSString then subclassing it is going to be a massive pain in comparison to categories.
Second...
Blocks are useful for capturing scope and context. They can also be passed around. So you can pass a block into an asynchronous call which then may be passed elsewhere. TBH you don't care where the block is passed or where it is finally called from. The scope captured at the time of creating the block is captured too.
Yes, you can use methods too. But they both have different uses.
Your questions are a bit odd. It's like asking...
Why do hammers exist when we can just use wrenches?
You can't use subclassing when someone else is creating the objects. For instance, NSString is returned from hundreds of system APIs, and you can't change them to return MyImprovedString.
Functions split up the logic; blocks allow you to write it closer together. Like:
[thing doSomethingAndWhenFinishedDo: ^{ some_other_thing; }];
the same code written with functions would put the second part of the logic several lines away in the file. If you have a few nested scopes in your logic then blocks can really clean it up.
Why do we needed category when we can use a subclass?
Categories let you expand the API of existing classes without changing their type. Subclassing does the same thing but introduces a new type. Additionally subclassing lets you add state.
Why we needed blocks when we can use functions?
Block objects are a C-level syntactic and runtime feature. They are similar to standard C functions, but in addition to executable code they may also contain variable bindings to automatic (stack) or managed (heap) memory. A block can therefore maintain a set of state (data) that it can use to impact behavior when executed.
You can use blocks to compose function expressions that can be passed to API, optionally stored, and used by multiple threads. Blocks are particularly useful as a callback because the block carries both the code to be executed on callback and the data needed during that execution
Category : It is used if we want to add any method on a given class whose source is not known. This is basically used when we want to alter the behaviour of any Class.
For example : If we want to add a method on NSString to reverse a string we can go for categories.
Subclassing : If we want to modify state as well as behaviour of any class or override any methods to alter the behaviour of the parent class then we go for subclassing.
For example : We subclass UIView to alter its state and behaviour in our iOS code.
Reference :
When to use categories and when to use subclassing?
What is the difference between inheritance and Categories in Objective-C
We need new method but we don't need new class so we need category.
We need function but we don't need named function so we need block.

Resources