XPC method not invoked with NSArray of NSValues as parameter - objective-c

I have an XPC service compiled 32-bit for OS-X. One of it's methods takes a single argument as a parameter, and calls a given block back on the main process.
This block takes 3 NSStrings and an NSArray that's supposed to contain NSValues solely. Each NSValue object holds an NSRect.
For some reason, the given block is not being called when the NSArray is not nil.
If instead of holding NSValues I let the array hold NSStrings, the block is being called correctly.
I'm not sure how to approach this, as there is no apparent reason for this to happen. According to the apple documentation, NSValue does conform to NSSecureCoding.
I even tried whitelisting the NSValue class (this shouldn't really be needed) using:
NSSet *readerSelectionClasses =
[NSSet setWithObjects:[NSArray class], [NSValue class], nil];
[newConnection.exportedInterface setClasses:readerSelectionClasses forSelector:#selector(MyMethod:WithReply:) argumentIndex:3 ofReply:YES];
This doesn't seem change anything.
Any idea how to pass the NSArray? I guess I could format all NSRects to NSStrings, and pass an array of NSStrings, which I know works, but this would lead to a performance decrease I would rather avoid.

Related

What if assigning NSMutableArray to NSArray without using 'copy'?

I'm new into Obj-C.
I would like to know will there be any problems if I assigning NSMutableArray to NSArray as like example code below:
NSMutableArray *mutableArray = [NSMutableArray arrayWithObjects:#"item1", #"item2", nil];
NSArray *array = mutableArray;
I know that if i use [mutableArray copy] it will duplicate the array as new set. My question is will my approach conflict with any guidance or will have any problems?
Thanks.
Both pointers will refer to the same object. The nature and behavior of that object will remain the same. It is not aware nor affected by which pointers refer to it.
If the array is mutated, those mutations will be observable regardless of which pointer you use to message or examine the array.
The compiler will complain if methods present in NSMutableArray but not NSArray are sent via the array pointer. However, if you ignore the compiler's complaints, the methods will still work as normal. The static types of the pointers is only significant at compile time. They are not represented in the compiled program (except, possibly, in debugging information, but that doesn't affect runtime behavior).
The catch is this:
if mutableArray changed somehow, and the array still think of it self immutable.
Then, things might get out of control.
Other than this, I don't see much problem here...
Your array will stay mutable, but compiler will think that it is immutable. So it won't allow you to use methods specific for NSMutableArray without typecasting.

How memory is managed for an object that is created but not assigned to any pointer?

This might be a stupid question, but it keeps bothering me.
Say if we have a method that takes an NSString object as its parameter and does something with the NSString object,
- (void)someMethod:(NSString *)str
{
//do something with str
}
Consider this code
[someObject someMethod:[[NSString alloc] initWithFormat:#"Hello World!"]];
Since alloc has been used in creating the string as parameter of someMethod, it has to be balanced by release no matter explicitly in pre-ARC environment or implicitly under ARC. But it seems there is no way we can get a pointer to the string as we have never assigned it to any pointer.
So my question is, first, is this way of passing parameter prohibited in writing objective c code? If no, then how objects created this way get released? And finally, does this code lead to memory leak?
Just for the record, I understand the above code is written
NSString *string = [[NSString alloc] initWithFormat:#"Hello World!"];
[someObject someMethod:string];
// [string release]; depending on ARC or non-ARC
Well, in fact, that object is assigned to the variable named str, which is a parameter of your method. You can manage the memory inside your method via that pointer, although methods aren't supposed to take ownership of their arguments (except see below).
ARC knows what to do in this situation -- it will either autorelease the object or add a release once the method is finished.
Under MRR, your snippet would be a leak; the correct way to avoid that is also to send autorelease:
[someObject someMethod:[[[NSString alloc] initWithFormat:#"Hello World!"] autorelease]];
or to use your last snippet (putting the string into a temporary variable and releasing later).
As a slightly esoteric option, it is possible for your method to declare that it owns the argument, by using the ns_consumed attribute:
- (void)someMethod:(NSString *) __attribute__((ns_consumed)) str;
This indicates that your method should send release to the object before it returns -- ARC will also take care of that.
So my question is, first, is this way of passing parameter prohibited in writing objective c code?
No. It's perfectly legal.
If no, then how objects created this way get released?
ARC will take care of it for you. If you do your own reference counting, then you can add it to the autorelease pool before it goes out of scope:
[someObject someMethod:
[[[NSString alloc] initWithFormat:#"Hello World!"] autorelease]];
^^^^^^^^^^^
And finally, does this code lead to memory leak?
Not in ARC. In MRC, you would need to add the -autorelease.
The static analyzer would also point out that leak.
There's no reason to not write code as you ask for consideration on… nothing prohibited in the slightest. These objects get released in the same manner that any other object gets released. Your lack of a variable to store the pointer in at the top level isn't important because the Objective C runtime knows about the object.

Is there any way to monkey-patch or swizzle an NSArray (or other Class Cluster)?

Today I was working on a project in which I wanted to "alias" an alternative method for all instances of NSArray, and didn't think it would be too difficult with some good old-fashioned method swizzling.
I broke out JRSwizzle and…
[NSArray jr_swizzleMethod:#selector(objectAtIndex:) withMethod:#selector(objectAtIndex_accordingToMe:) error:nil];
To be clear, I paired this with the appropriate category on NSArray, an instance method called objectAtIndex_accordingToMe:.
However, I was just getting that same old object, at that same old index. Sigh. Ultimately, I figured out that despite not throwing any errors - I'm not going to achieve these results due to the fact that NSArray is a class cluster
I guess my question is more of an unwillingness to accept that "this" is really the end of the road trying to override NSArray methods. I mean, come on this is NSArray.. people must wanna muck around with it, no? One would think that Apple's foundation classes would be a prime target for swizzlers, everywhere!
So, is there a way to alter, alias, monkey-patch, override, or otherwise have your way with… an NSArray, etc. (without subclassing)?
It's not just that it's a class cluster. NSArray is toll-free bridged to CFArray, and you can't swizzle Core Foundation. So this is very unlikely to work in general.
But what are you trying to solve? If you want to add a new method, use a category. They work on class clusters just fine. Modifying the behavior of some built-in on NSArray seems a recipe for disaster (entertaining as it might be as an exercise).
Before going too far, you probably want to at least take a look at CFArray.c and understand how some of the underlying stuff is implemented.
EDIT: While I would never do this in production code, you may get some of what you want by hijacking individual array instances with ISA-swizzling. See ISASwizzle for some example code. The code explanation is in Chapter 20 of iOS:PTL. Search out for "isa swizzle" and you should find more on the net. It's how KVO is implemented. But with NSArray... wow, that's gotta be fragile.
Presumably you have a particular array for which you'd like this behavior. You can get that instance's class object, no matter what it is, and swizzle that quite easily:
[[myArray class] jr_swizzleMethod:#selector(objectAtIndex:) withMethod:#selector(objectAtIndex_accordingToMe:) error:nil];
There's also only a few concrete subclasses of NSArray:
NSArray * trees = [NSArray array];
NSArray * birds = [NSArray arrayWithObjects:#"Albatross", #"Budgerigar", #"Cardinal", nil];
NSMutableArray * dogs = [NSMutableArray arrayWithObjects:#"Airedale", #"Beagle", #"Collie", nil];
NSLog(#"%# %# %#", [trees class], [birds class], [dogs class]);
We get __NSArrayI for the first two and __NSArrayM for the third, so potentially (this is very fragile) you could use a runtime function to grab the class object by name:
[objc_getClass("__NSArrayI") jr_swizzleMethod:#selector(objectAtIndex:) withMethod:#selector(objectAtIndex_accordingToMe:) error:nil];

Releasing objects created by functions

I'm learning obj-c and I have a question about memory management:
Say I have a function that returns an NSDictionary, "fDictionary",
NSDictionary *fDictionary {
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:1], #"blah",nil];
return dict
}
that is called by a particular method:
-(int)fNumber {
NSDictionary *f = fDictionary();
return [[f objectForKey:#"blah"] intValue];
}
What I'm unclear about is how/where I should be releasing the NSDictionary object.
Should I release it in the method, or autorelease it in the function?
If the function was written properly, the dictionary is autoreleased, so you don't have to release it at all. It will be released soon, by the autorelease pool.
You only release what you yourself retain or copy. These are the things you "own". Be sure not to release them too early. The usual point is before the end of the function they are allocated or retained in, if they are local. If they are ivars, the best point is, usually, the dealloc of the class to which the ivar belongs.
Without knowing anything about fDictionary it's difficult to be sure, but the convention followed in most Object C code is as follows:
You own it if the instance was created with an alloc or copy
You own it if you retain it
Otherwise you don't own it
If you don't own it you should not release it.
So by convention, the function would return an autoreleased object and you wouldn't need any extra management in your method.
The general rule is if your code alloc's something, you need to release or auto-release it.
If this was someone else's function, you would expect that the returned dictionary was autoreleased - which is the convention here. I would ensure that fDictionary returns an autoreleased NSDictionary.
If you have received an object from a method which name begins with “alloc”, “new”, “copy”, or “mutableCopy”, you have to release or auto-release it. Otherwise it is already autoreleased.
If you have retained something, you have to release it, nothing else will do that for you.
Every Obj-C programmer must read Memory Management Guide.
No.
NSDictionary dictionaryWithObjectsAndKeys: (which is really just [[[NSDictonary alloc]initWithObjectsAndKeys:, nil]autorelease]) returns an autoreleased NSDictionary. This means the dictionary will automatically be released when the computer decides it is no longer needed.
If in fDictionary() the dictionary was alloced, you would need to release it manually. It is a rule of thumb to always return autoreleased objects from functions/methods, so the user of the functions/methods does not have to worry about memory management.

A method that takes both NSArray and NSMutableArray

I want to create a method that can take an NSMutableArray or an NSArray object.
I think I can just use (id) as the parameter type... or convert the NSArray to NSMutableArray before passing. However I'm not really happy with these solutions.
In other languages I might pass an IList or some shared object that they both inherit from...
I need to enumerate through the array in my method.
What is the way people would typically do this in objective c?
Take NSArray. NSMutableArray derives from NSArray, so as long as you're only using the NSArray members (such as read-only enumeration), you'll be safe.
Relevant documentation (from Apple's developer site):
NSMutableArray class reference
NSArray class reference
Since NSMutableArray is a subclass of NSArray, just have your method take an NSArray parameter. That way, it will take anything that is or is a subclass of NSArray.
Use NSArray* -- NSMutableArray inherits from it and you can iterate both as if they were NSArrays.
I would stick with NSArray as the parameter because I prefer to use immutable objects wherever possible (looser coupling), and then use the -mutableCopy method when required to send them to an to a function that needs to modify the array.