What method families exist in objective-c/cocoa for iOS? - objective-c

I am a experienced developer that is new to iOS developement (on iPhone in particular). A project I am working on is using Automatic Reference Counting (ARC).
I was doing some research on ARC and came across this document: http://clang.llvm.org/docs/AutomaticReferenceCounting.html and in a section titled: "Retained return values" it states that an attribute can be used to indicate that the caller expects to take ownership of a +1 retain count. It also goes on to state that ARC will automatically add the attribute to methods if it detects it is in particular method families (it specifically names: alloc, copy, init, mutableCopy, and new)
From further reading it seems that method families are simply method naming conventions. My understanding is that if the method name starts with a method family then it is in that method family. So for example
+(id) init
+(id) initWithName:(NSString*)name
are both part of the init method family.
My question is: Is there a formal list of defined Method Families for iOS development and if so, what are they / where might I find it?
below is the section llvm.org I mentioned above:
Section 3.2.2: Retained return values states:
A function or method which returns a retainable object pointer type
may be marked as returning a retained value, signifying that the
caller expects to take ownership of a +1 retain count. This is done by
adding the ns_returns_retained attribute to the function or method
declaration, like so:
id foo(void) __attribute((ns_returns_retained));
- (id) foo __attribute((ns_returns_retained)); This attribute is part of the type of the function or method.
When returning from such a function or method, ARC retains the value
at the point of evaluation of the return statement, before leaving all
local scopes.
When receiving a return result from such a function or method, ARC
releases the value at the end of the full-expression it is contained
within, subject to the usual optimizations for local values.
Rationale: this formalizes direct transfers of ownership from a callee
to a caller. The most common scenario this models is the retained
return from init, alloc, new, and copy methods, but there are other
cases in the frameworks. After optimization there are typically no
extra retains and releases required.
Methods in the alloc, copy, init, mutableCopy, and new families are
implicitly marked attribute((ns_returns_retained)). This may be
suppressed by explicitly marking the method
attribute((ns_returns_not_retained)).
It is undefined behavior if the method to which an Objective-C message
send statically resolves has different retain semantics on its result
from the method it dynamically resolves to. It is undefined behavior
if a block or function call is made through a static type with
different retain semantics on its result from the implementation of
the called block or function.
Rationale: Mismatches with returned results will cause over-retains or
over-releases, depending on the direction. Again, the rule about
function calls is really just an application of the existing C/C++
rule about calling functions through an incompatible function type.

Section 5 of the same document is titled "Method Families". It lists all the currently defined families, which are the ones you identified above; alloc, new, copy, mutableCopy, and init. It also lists the criteria for being part of that family. Mostly, it's just based on the method name, but it also depends on the return type. For example, a member of the copy family must return an object; a copy method that has a void return type will not be considered part of the copy method family.

I don't know that I've seen a formal list of method families, but your analysis is basically correct. I believe the only method naming conventions that have compiler-enforced semantics are those mentioned in your post, namely alloc, init, copy (and mutableCopy), and new. Even before/without ARC, the clang static analyzer included in Xcode uses those naming conventions to find memory management problems, and they're also the basis of the longstanding memory management rules for Objective-C programmers prior to ARC.
Namely, if you create an object using a method that begins with init, copy, mutableCopy or new, you "own" that object and are responsible for releasing it later. Objects created or returned by methods with any other name, are not owned by you, the caller, and if you want to keep a reference to them, you must retain them. Every retain you make must be balanced by a later release, when you're done with the object reference. Finally, calling autorelease on an object puts it in the innermost autorelease pool. The pool is responsible for releasing the object later, where later is sometime after the current scope. So, release and autorelease are both valid ways of relinquishing your retain on an object.
Now, the rules I've set forth shouldn't (and can't) be followed by you, the programmer, under ARC. However, ARC is essentially a system whereby the compiler with help from the static analyzer knows these rules and inserts the necessary memory management calls for you at compile time. So, if you're looking to develop an understanding of what ARC is doing behind-the-scenes, understanding these rules is a good start.
This turned out a bit longwinded, but the point is that the methods you've named are the only ones I know of that have this enforced naming convention in Objective-C, and it stems from the memory management rules set forth above. There are other naming conventions in Objective-C, to be sure, but they're standard style conventions, not something that's enforced anywhere.

Look at official Apple Developer documentation about Memory Management Rules. Seems, your list is complete: “alloc”, “new”, “copy”, or “mutableCopy” (only 4 keywords).

I would include the convenience constructors provided by some Cocoa classes:
- +stringWith* // Various ways to make NSString objects
- +arrayWith*, +dictionaryWith*, etc. // Make collections
- +dateWith* // Make NSDate objects
- etc. // Many, many others
They all return a new, autoreleased instance of the class they are sent to - except for some special cases, see for instance #Peter Hosey's comment.
I don't know if there are any formal rules, but the pattern is that the constructor name is composed of the class name without the NS part (and without the Mutable part, too, for mutable classes) followed by With<Parameter Type>: and one or more parameters. The name begins with a lower case letter (except the usual suspects, like URLWithString:.)
For instance, the following line provides an autoreleased NSArray instance with a single element:
[NSArray arrayWithObject: #"Test"]
I don't know if there are any special rules in the compiler to recognize this type of constructor.

Related

Reference counting return value of MTLCreateSystemDefaultDevice

I am using Objective-C without ARC and want to know if I need to free the device returned by MTLCreateSystemDefaultDevice when used like so:
id<MTLDevice> device = MTLCreateSystemDefaultDevice()
I am not sure how id<MTLDevice> works to maintain a reference count. Based on the naming conventions for memory management, I am assuming MTLCreateSystemDefaultDevice does not add reference (but could be wrong), but maybe assigning to id<MTLDevice> results in a retain being called?
Yes, you need to release the object when you're done with it. For C functions (rather than Objective-C messages), the relevant naming convention is the Create Rule. Because the function has "Create" in the name, it returns a +1 reference that you are responsible for releasing. (The fact that it's returning an Objective-C type rather than a Core Foundation type isn't important.)
As to id<MTLDevice>, that's id, the generic object type of Objective-C, with a protocol designation <MTLDevice> indicating that the object pointed to by device conforms to the MTLDevice protocol. (Somewhat oddly, that's actually more restrictive than id alone, since the compiler will then warn if you try to invoke methods other than those supported by MTLDevice and its super-protocols.) Not that the object is of some concrete class behind the scenes, it's just a private implementation detail.

LLVM doesn't like Objective-C class method names starting with keyword 'new' [duplicate]

I have experience with pure ARC coding. As a compiler feature it honors Objctive-C method family putting right retain/release calls whenever neeeded.
All methods that start with alloc, mutableCopy, copy and new create a new object. They increase the retain count. As a consequence, ARC will release any pointer (and hence the object associated with it) when I no longer need it.
I think that problems could arise when I write methods that do not follow naming conventions. For example, if I write a method like newCustomer that in a first version returns an autoreleased object while in a second version does not, what could happen?
In particular, my questions are the following (they belong to the same reasoning):
What happens if the calling and called code are both compiled with ARC?
(a) What happens if the calling code is compiled with ARC while the called is compiled with non-ARC?
(b) What happens if the calling code is compiled with non-ARC while the called is compiled with ARC?
It would be appreciated an answer that shows how ARC works under the hood (objc_release, objc_retainAutoreleasedReturnValue, etc.).
Thank you in advance.
A method named newCustomer would fall within the new method family and is thus implicitly marked as returning an retained object. When both calling and called code is compiled with ARC, then ARC balances the extra retain with a release in the caller:
When returning from such a function or method, ARC retains the value
at the point of evaluation of the return statement, before leaving all
local scopes.
When receiving a return result from such a function or method, ARC
releases the value at the end of the full-expression it is contained
within, subject to the usual optimizations for local values.
Source
If newCustomer is implemented with manual reference counting and violates the naming convention (i.e., does not return a retained object), then the caller can either over release or under release, depending on the circumstances.
If the caller uses ARC, then the object returned from newCustomer will be overreleased - likely causing the program to crash. This is because the calling code will participate in the second half of the above process, without having had a corresponding retain performed prior to that.
If the calling code is not compiled with ARC, but the called code is (thus correctly implementing returning a retained object), then the behavior depends on the programmer following the naming conventions. If they release the returned value, then the object's reference count will be correctly managed. However, if the programmer believes that their new... method does violate the naming convention, and fails to manually insert a release in the calling code, then the object that was returned will leak.
All in all, as Martin R. points out in the comments, the critical determination is whether the naming conventions are followed in any environment including manual reference counting.
Just like any other language, when you violate some of the basic assumptions of the language you wander into the area of undefined behavior. At some point in the future, Apple may modify the internals of how -new... does reference counting. It is up to Apple to make sure that code which conforms to the expected use works, but they won't do that for non-conforming uses.
If you need to know what the actual behavior is for a particular version of a compiler running on a particular system, then you must test for it. Don't assume that behavior will be the same for other compilers or versions of the runtime.
In the end, undefined behavior is undefined behavior. When you build code relying on it, you will eventually be affected by a subtle and difficult to diagnose defect.

Cocoa blocks as strong pointers vs copy

I did work several times with blocks as with pointers to which i had strong reference
I heard that you should use copy, but what is the implication in working with blocks as pointers and not with the raw object?
I never got a complain from the compiler, that i should not use
#property (nonatomic, strong) MyBlock block;
but should use
#property (nonatomic, copy) MyBlock block;
as far as i know, the block is just an object, so why to preferrer copy anyway?
Short Answer
The answer is it is historical, you are completely correct that in current ARC code there is no need to use copy and a strong property is fine. The same goes for instance, local and global variables.
Long Answer
Unlike other objects a block may be stored on the stack, this is an implementation optimisation and as such should, like other compiler optimisations, not have direct impact on the written code. This optimisation benefits a common case where a block is created, passed as a method/function argument, used by that function, and then discarded - the block can be quickly allocated on the stack and then disposed of without the heap (dynamic memory pool) being involved.
Compare this to local variables, which (a) created on the stack, (b) are automatically destroyed when the owning function/method returns and (c) can be passed-by-address to methods/functions called by the owning function. The address of a local variable cannot be stored and used after its owning function/method has return - the variable no longer exists.
However objects are expected to outlast their creating function/method (if required), so unlike local variables they are allocated on the heap and are not automatically destroyed based on their creating function/method returning but rather based on whether they are still needed - and "need" here is determined automatically by ARC these days.
Creating a block on the stack may optimise a common case but it also causes a problem - if the block needs to outlast its creator, as objects often do, then it must be moved to the heap before its creators stack is destroyed.
When the block implementation was first released the optimisation of storing blocks on the stack was made visible to programmers as the compiler at that time was unable to automatically handle moving the block to the heap when needed - programmers had to use a function block_copy() to do it themselves.
While this approach might not be out-of-place in the low-level C world (and blocks are C construct), having high-level Objective-C programmers manually manage a compiler optimisation is really not good. As Apple released newer versions of the compiler improvements where made. Early on it programmers were told they could replace block_copy(block) with [block copy], fitting in with normal Objective-C objects. Then the compiler started to automatically copy blocks off stack as needed, but this was not always officially documented.
There has been no need to manually copy blocks off the stack for a while, though Apple cannot shrug off its origins and refers to doing so as "best practice" - which is certainly debatable. In the latest version, Sept 2014, of Apple's Working with Blocks, they stated that block-valued properties should use copy, but then immediately come clean (emphasis added):
Note: You should specify copy as the property attribute, because a block needs to be copied to keep track of its captured state outside of the original scope. This isn’t something you need to worry about when using Automatic Reference Counting, as it will happen automatically, but it’s best practice for the property attribute to show the resultant behavior.
There is no need to "show the resultant behavior" - storing the block on the stack in the first place is an optimisation and should be transparent to the code - just like other compiler optimisations the code should gain the performance benefit without the programmer's involvement.
So as long as you use ARC and the current Clang compilers you can treat blocks like other objects, and as blocks are immutable that means you don't need to copy them. Trust Apple, even if they appear to be nostalgic for the "good old days when we did things by hand" and encourage you to leave historical reminders in your code, copy is not needed.
Your intuition was right.
You are asking about the ownership modifier for a property. This affects the synthesized (or auto-synthesized) getter and/or setter for the property if it is synthesized (or auto-synthesized).
The answer to this question will differ between MRC and ARC.
In MRC, property ownership modifiers include assign, retain, and copy. strong was introduced with ARC, and when strong is used in MRC, it is synonymous with retain. So the question would be about the difference between retain and copy, and there is a lot of difference, because copy's setter saves a copy of the given value.
Blocks need to be copied to be used outside the scope where it was created (with a block literal). Since your property will be storing the value as an instance variable that persists across function calls, and it's possible that someone will assign an unoccupied block from the scope where it was created, the convention is that you must copy it. copy is the right ownership modifier.
In ARC, strong makes the underlying instance variable __strong, and copy also makes it __strong and adds copying semantics to the setter. However, ARC also guarantees that whenever a value is saved into a __strong variable of block-pointer type, a copy is done. Your property has type MyBlock, which I assume is a typedef for a block pointer type. Therefore, a copy will still be done in the setter if the ownership qualifier were strong. So, in ARC, there is no difference between using strong and copy for this property.
If this declaration might be used in both MRC and ARC though (e.g. a header in a library), it would be a good idea to use copy so that it works correctly in both cases.
what is the implication in working with blocks as pointers and not with the raw object?
You are never using the raw value, you always have a pointer to a block: a block is an object.
Looking at your specific example, I am assuming you want to keep the block around, "so why to preferrer copy anyway"enter code here? Well, it's a matter of safety (this example is taken from Mike Ash blog). Since blocks are allocated on the stack (and not on the heap as the rest of the objects in objective-c), when you do something like this:
[dictionary setObject: ^{ printf("hey hey\n"); } forKey: key];
You are allocating the block on the stack frame of your current scope, so when the scope ends (for example your returning the dictionary), the stack frame is destroyed and the block goes with it. So you got yourself a dangling pointer. I would advise reading Mike's article fully. Anyway, you can go with a strong property if when you are assigning the block you copy it:
self.block = [^{} copy];
Edit: After looking at Mike's article date, I am assuming this was the behaviour Pre-ARC. On ARC it seems it's working as expected, and it won't crash.
Edit2: After experimenting with Non-ARC it doesn't crash as well. But this example shows different results depending on the use of ARC or not:
void (^block[10])();
int i = -1;
while(++i < 10)
block[i] = ^{ printf("%d\n", i); };
for(i = 0; i < 10; i++)
block[i]();
Quoting Mike Ashe on the different outcomes:
The reason it prints out ten 9s in the first case is quite simple: the
block that's created within the loop has a lifetime that's tied to the
loop's inner scope. The block is destroyed at the next iteration of
the loop, and when leaving the loop. Of course, "destroy" just means
that its slot on the stack is available to be overwritten. It just
happens that the compiler reuses the same slot each time through the
loop, so in the end, the array is filled with identical pointers, and
thus you get identical behavior.
As far as I understand copy is required when the object is mutable. Use this if you need the value of the object as it is at this moment, and you don't want that value to reflect any changes made by other owners of the object. You will need to release the object when you are finished with it because you are retaining the copy.
On the other hand, strong means that you own the object until it is needed. It is a replacement for the retain attribute, as part of ARC.
Source: Objective-C declared #property attributes (nonatomic, copy, strong, weak)
Note: You should specify copy as the property attribute, because a block needs to be copied to keep track of its captured state outside of the original scope. This isn’t something you need to worry about when using Automatic Reference Counting, as it will happen automatically, but it’s best practice for the property attribute to show the resultant behavior. For more information, see Blocks Programming Topics.

Objective-C naming conventions with ARC and possible caveats

I have experience with pure ARC coding. As a compiler feature it honors Objctive-C method family putting right retain/release calls whenever neeeded.
All methods that start with alloc, mutableCopy, copy and new create a new object. They increase the retain count. As a consequence, ARC will release any pointer (and hence the object associated with it) when I no longer need it.
I think that problems could arise when I write methods that do not follow naming conventions. For example, if I write a method like newCustomer that in a first version returns an autoreleased object while in a second version does not, what could happen?
In particular, my questions are the following (they belong to the same reasoning):
What happens if the calling and called code are both compiled with ARC?
(a) What happens if the calling code is compiled with ARC while the called is compiled with non-ARC?
(b) What happens if the calling code is compiled with non-ARC while the called is compiled with ARC?
It would be appreciated an answer that shows how ARC works under the hood (objc_release, objc_retainAutoreleasedReturnValue, etc.).
Thank you in advance.
A method named newCustomer would fall within the new method family and is thus implicitly marked as returning an retained object. When both calling and called code is compiled with ARC, then ARC balances the extra retain with a release in the caller:
When returning from such a function or method, ARC retains the value
at the point of evaluation of the return statement, before leaving all
local scopes.
When receiving a return result from such a function or method, ARC
releases the value at the end of the full-expression it is contained
within, subject to the usual optimizations for local values.
Source
If newCustomer is implemented with manual reference counting and violates the naming convention (i.e., does not return a retained object), then the caller can either over release or under release, depending on the circumstances.
If the caller uses ARC, then the object returned from newCustomer will be overreleased - likely causing the program to crash. This is because the calling code will participate in the second half of the above process, without having had a corresponding retain performed prior to that.
If the calling code is not compiled with ARC, but the called code is (thus correctly implementing returning a retained object), then the behavior depends on the programmer following the naming conventions. If they release the returned value, then the object's reference count will be correctly managed. However, if the programmer believes that their new... method does violate the naming convention, and fails to manually insert a release in the calling code, then the object that was returned will leak.
All in all, as Martin R. points out in the comments, the critical determination is whether the naming conventions are followed in any environment including manual reference counting.
Just like any other language, when you violate some of the basic assumptions of the language you wander into the area of undefined behavior. At some point in the future, Apple may modify the internals of how -new... does reference counting. It is up to Apple to make sure that code which conforms to the expected use works, but they won't do that for non-conforming uses.
If you need to know what the actual behavior is for a particular version of a compiler running on a particular system, then you must test for it. Don't assume that behavior will be the same for other compilers or versions of the runtime.
In the end, undefined behavior is undefined behavior. When you build code relying on it, you will eventually be affected by a subtle and difficult to diagnose defect.

Conflict between memory management descriptions in ObjC book and official docs

I'm trying to learn/understand what happens and why when working with or creating various objects. (Hopefully to LEARN from the docs.)
I'm reading "Programming in Objective-C 2.0" (2nd edition, by Steven Kochan). On page 408, in the first paragraph is a discussion of retain counts:
Note that its reference count then goes to 2. The addObject: method does this automatically; if you check your documentation for the addObject: method, you will see this fact described there.
So I read the addObject: docs:
Inserts a given object at the end of the array.
There, the description is missing, while other items, like arrayByAddingObject:, state it:
Returns a new array that is a copy of the receiving array with a given object added to the end.
Where in the reference does it indicate that addObject: increases the retain count? Given the presence of ARC, I should still understand what these methods are doing to avoid bugs and issues. What does ARC bring to this? (Going to read that again...)
Great question, I'm glad to see someone actually reading the docs and trying to understand them!
Since you are looking for how to research answers using Apple's documentation more so than the actual answer itself, here is how I found the answer:
First I look at the class reference for addObject: which is a method of NSMutableArray and there is no mention of memory management.
Then I look at the Overview section at the top... Hmmm, still no luck.
Since the behavior might be inherited from a parent class, I look at the Inherits from section at the top of the class reference and see that NSArray is the most immediate parent. Let's check there:
Under the Overview There is one small section about retain's:
Special Considerations
In most cases your custom NSArray class should conform to Cocoa’s
object-ownership conventions. Thus you must send retain to each object
that you add to your collection and release to each object that you
remove from the collection. Of course, if the reason for subclassing
NSArray is to implement object-retention behavior different from the
norm (for example, a non-retaining array), then you can ignore this
requirement.
Okay, I'm still not happy... Where next? The parent class of NSArray is NSObject and I know that it won't be covered there in this case (from experience) so I won't bother checking that. (If the parent was another class or something that might be covered by NSObject, I would keep moving up the tree until I found something.)
The Companion Guides usually contains a lot of good information for these types of classes. Let's try the first one, Collections Programming Topics.
The first section (after Overview) is Accessing Indexes and Easily Enumerating Elements: Arrays. Sounds promising! Click on Relevant Chapters: “Arrays: Ordered Collections”
There it is under Array Fundamentals along with a link to even more information:
And when you add an object to an NSMutableArray object, the object
isn’t copied, (unless you pass YES as the argument to
initWithArray:copyItems:). Rather, an object is added directly to an
array. In a managed memory environment, an object receives a retain
message when it’s added; in a garbage collected environment, it is
strongly referenced. When an array is deallocated in a managed memory
environment, each element is sent a release message. For more
information on copying and memory management, see “Copying
Collections.”
The book must be referring to out of date documentation because you are correct it doesn't mention anything about the retain count. It does in fact retain the object though. The way you need to think of it is not in terms of retain counts (which are useless) but rather ownership. Especially so when using ARC.
When you add an object to an NSMutableArray, it is taking ownership of that object (in ARC terminology it has a strong reference to it).
"What does ARC bring to this?"
ARC does nothing different. All ARC does (besides some optimization) is add the same release, retain, and autorelease statements that you would add yourself without using ARC. All you need to care about is that once you add an object to the array, it will live at least as long as the array.
And the arrayByAddingObject: method creates a new NSArray (or NSMutableArray) containing the object you're passing, and keeps a strong reference to the passed object. The actual array object that it creates has no references yet unless you assign it to either an ivar, property, or local variable. What you assign it to determines it's lifespan.
Basically even without ARC, it's best to think of object life-cycles in terms of ownership, ARC just formalizes that. So because of that, when using the frameworks, it doesn't matter when retains happen or don't happen, you are only responsible for your objects until you pass ownership to another object and you can trust that the framework will keep the object alive as long as it needs it.
Now of course you have to intuit what constitutes ownership. For instance delegate properties are often assign, or in ARC unsafe_unretained or weak, to prevent circular retains cycles (where two objects each retain each other), though are sometimes retained/strong so you need to look into those on a case by case basis.
And also in cases like key value observing and NSNotification observing the object you are observing does not retain the observer.
But those are really exceptions to the rule. Generally you can assume a strong reference.
Regarding this sentence above: "The actual array object that it creates has no references yet unless you assign it to either an ivar, property, or local variable. What you assign it to determines it's lifespan." I'll try to explain:
When you run this piece of code: [someArray arrayByAddingObject:someObject]; you've instantiated a new NSArray or NSMutableArray object (depending on which object type someArray is) but you haven't actually assigned it to any reference. That means that if you're using ARC, it may be immediately released afterwards, or if not using ARC, it will be released when it's autoreleasepool is drained (probably on the next iteration of that thread's runloop).
Now if instead you did this: NSArray *someOtherArray = [someArray arrayByAddingObject:someObject]; you now have a reference to the newly created array, called someOtherArray. In this case, this is a local variable who's scope is only within whichever set of { } it resides (so it could be inside an if statement, a loop, or a method. Now if you do nothing else with it, it will die sometime after it's scope ends (it isn't guaranteed to die right away, but that isn't important, you just can't assume it lives longer).
Now if in your class you have an iVar (instance variable) declared in the header like NSArray *someOtherArray; (which is strong by default in ARC) and you run someOtherArray = [someArray arrayByAddingObject:someObject]; somewhere in your class, the object will live until you either remove the reference (someOtherArray = nil), you overwrite the reference (someOtherArray = someThirdArray), or the class is deallocated. If you were not using ARC, you would have to make sure to retain that to achieve the same effect (someOtherArray = [[someArray arrayByAddingObject:someObject] retain]; which is essentially what ARC is doing behind the scenes).
Or you may have a property declared instead like #property (nonatomic, strong) NSArray *someOtherArray in which self.someOtherArray = [someArray arrayByAddingObject:someObject]; would achieve the same effect but would use the proprety accessor (setSomeOtherArray:) or you could still use someOtherArray = [someArray arrayByAddingObject:someObject]; to set the iVar directly (assuming you #synthesized it).
Or assuming non-ARC, you might have declared the property like #property (nonatomic, retain) NSArray *someOtherArray in which self.someOtherArray = [someArray arrayByAddingObject:someObject]; would behave exactly as ARC would, but when setting the iVar directly you would still need to add that retain manually.
I hope that clears things up a bit, please let me know if there's anything I glossed over or left out.
As you mentioned in your comment, the key here is intuitively knowing when an object would be considered owned by another one or not. Luckily, the Cocoa frameworks follow a pretty strict set of conventions that allow you to make safe assumptions:
When setting an NSString property of a framework object (say the text property of a UILabel for example) it is always copied (if anyone knows of a counter-example, please comment or edit). So you don't have to worry about your string once you pass it. Strings are copied to prevent a mutable string from being changed after it's passed.
When setting any other property other than delegate, it's (almost?) always retained (or strong reference in ARC)
When setting delegate properties, it's (almost?) always an assign (or weak reference) to prevent circular retain cycles. (For instance, object a has a property b that is strong referenced and b has a strong referenced delegate property. You set a as the delegate for b. Now a and b are both strongly referencing each other, and neither object will ever reach a retain count of 0 and will never reach it's dealloc method to dealloc the other object. NSURLConnection is a counter-example that does strongly reference it's delegate, because it's delegate is set via a method -- see that convention below -- and it's convention to nil out or release an NSURLConnection after it completes rather than in dealloc, which will remove the circular retain)
When adding to an array or dictionary, it's always retained (or strong reference).
When calling a method and passing block(s), they are always copied to move them from the stack (where they are initially created for performance purposes) into the heap.
Methods that take in object parameters and don't return a result immediately are (always? I can't think of any that don't) either copying or retaining (strong referencing) the parameters that you pass to ensure that the method can do what it needs to with them. For instance, NSURLConnection even retains it's delegate because it's passed in via a method, whereas when setting the delegate property of other objects will not retain, as that is the convention.
It's suggested that you follow these same conventions in your own classes as well for consistency.
Also, don't forget that the headers of all classes are available to you, so you can easily see whether a property is retain or assign (or strong or weak). You can't check what methods do with their parameters, but there's no need because of the convention that parameters are owned by the receiver.
In general, you should look in the "most global" spot for information about anything in the Cocoa APIs. Since memory management is pervasive across the system APIs and the APIs are consistent in their implementation of the Cocoa memory management policy, you simply need to read and understand the Cocoa memory management guide.
Once understood, you can safely assume that all system APIs implement to that memory management policy unless explicitly documented otherwise.
Thus, for NSMutableArray's addObject: method, it would have to retain the object added to the array or else it would be in violation of that standard policy.
You'll see this throughout the documentation. This prevents every method's documentation from being a page or more long and it makes it obvious when the rare method or class implements something that is, for whatever reason (sometimes not so good), an exception to the rule.
In the "Basic Memory Management Rules" section of the memory management guide:
You can take ownership of an object using retain.
A received object is normally guaranteed to remain valid within the
method it was received in, and that method may also safely return the
object to its invoker. You use retain in two situations: (1) In the
implementation of an accessor method or an init method, to take
ownership of an object you want to store as a property value; and (2)
To prevent an object from being invalidated as a side-effect of some
other operation (as explained in “Avoid Causing Deallocation of
Objects You’re Using”).
(2) is the key; an NS{Mutable}Array must retain any added object(s) exactly because it needs to prevent the added object(s) from being invalidated due to some side-effect. To not do so would be divergent from the above rule and, thus, would be explicitly documented.