Given NSArray *tagsArray and NSMutableDictionary *cache not empty.
This:
for (Tag *tag in tagsArray) {
NSString *name = tag.name;
[cache setObject:tag forKey:name];
}
should not be slower than this:
for (Tag *tag in tagsArray) {
[cache setObject:tag forKey:tag.name];
}
?
the __strong var 'name' would not use an implicit retain/release by ARC ? The compiler will actually generate the second from the first ?
Yes, it IS the same for ARC, because there's no other code that interacts with "name" variable in first example.
For future, try to understand that ARC modifies your code for better performance and optimization, and not vice versa.
Here's the link with entire documentation for ARC - must know - http://clang.llvm.org/docs/AutomaticReferenceCounting.html
If ChildClass objecA, objecB.... has an instance variable, and ParentClass tries to assign the ChildClass's instance variable (which is an instance variable of ParentClass and strong pointer),
then ChildClass' object acts like the same object. Although it is not the same. Definitely not same.
Related
To define a weak references for objects in block i use something like this
MyViewController *__weak weakSelf= self;
UILabel *__weak weakLabel=ALabel;
///the block code with some examples
up2.completionBlock = ^(NSDictionary *headers, NSString *responseString) {
[weakSelf aMethodInTheController];
[weakLabel setHidden:NO];
};
I have problem with a bool, how i can declare a weak reference to a bool to avoid the warnings "capturing self strongly in this block is likely to lead to a retain cycle" ?
Not works with:
Bool *__weak weakFlag=Aflag;
Well, it's not obvious what you are trying to do here.
There are two possibilities. Perhaps you need to pass a parameter to the block. So there is a variable of type bool or BOOL (they are similar for the purposes of this question) and you want to use it in the block.
Then, good news! You don't need anything at all. Just declare
BOOL some_bool = (YES or NO or some calculation);
and use it later in the block. This works because Boolean types are primitive (they are some kind of integer) and not smart enough to participate in memory management. So the compiler doesn't worry much; it just grabs the value of this variable when the block is created and copies it into the block.
Here's the relevant documentation:
Only the value is captured, unless you specify otherwise. This means that if you change the external value of the variable between the time you define the block and the time it’s invoked, ...
Alternatively, perhaps you want to have a variable which can take logical values and which can be changed by some other object in the time between you create the block and the time when it is run. In that case you need to
wrap boolean into NSNumber
store the strong reference to this NSNumber somewhere in your object
pass it as a weak pointer to the block
E.g.
// somewhere in the interface
#property NSNumber *someImportantFlag
__weak NSNumber *weakFlag = someImportantFlag;
... ^{ ... if(weakFlag.boolValue) ... weakFlag = #(NO); ...}
Thanks to the commenters who made me reread the question and my answer.
I'm trying to use blocks in a way where I provide a reference to the object which retains the block, as follows:
typedef void(^RunBlock)(__weak Thing *block_owner, ThingFinishBlock finish);
where Thing has a property run_block, of the type RunBlock.
Thing *thing = [Thing thingWithBlock^(Thing *owner, ThingFinishBlock finish) { ... }];
Calling the run_block from within the Thing goes something like this:
__weak typeof(self) this = self;
_finish_block = ^(){ ... }
self.run_block(this, _finish_block);
So what I'm wondering now is, is it safe to define the run_block's first parameter Thing *owner without prefixing it with __weak, or will this cause a retain loop? I'm unsure, as the pointer is already defined as __weak in the typedef, and the given parameter is already __weak.
^(__weak Thing *owner ...){ ... }
As opposed to
^(Thing *owner, ...) { ... }
Thanks!
No, __weak in parameters is not part of the function type itself.
typedef void(^RunBlock)(__weak Thing *block_owner, ThingFinishBlock finish);
is the same as
typedef void(^RunBlock)(Thing *block_owner, ThingFinishBlock finish);
It's where you implement the block that the __weak in the parameter matters.
Also, I have no idea why you think this has anything to do with retain cycles.
I'm trying to implement the countByEnumeratingWithState:objects:count: method from the NSFastEnumeration protocol on a custom class.
So far I have it iterating through my objects correctly, but the objects that are returned aren't Objective-C objects but rather the core foundation equivalents.
Here's the part of the code that sets the state->itemsPtr:
MyCustomCollection.m
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState *)state
objects: (id __unsafe_unretained *)buffer
count: (NSUInteger)bufferSize {
// ... skip details ...
NSLog(#"Object inside method: %#", someObject);
state->itemsPtr = (__unsafe_unretained id *)(__bridge void *)someObject;
// ... skip details ...
}
Then I call the 'for..in' loop somewhere else on like this
SomeOtherClass.m
MyCustomCollection *myCustomCollection = [MyCustomCollection new];
[myCustomCollection addObject:#"foo"];
for (id object in myCustomCollection) {
NSLog(#"Object in loop: %#", object);
}
The console output is:
Object inside method: foo
Object in loop: __NSCFConstantString
As you can see, inside the NSFastEnumeration protocol method the object prints fine, but as soon as it gets cast to id __unsafe_unretained * I lose the original Objective-C corresponding class.
To be honest I'm not quite sure how the (__unsafe_unretained id *)(__bridge void *) casting works in this case. The (__unsafe_unretained id *) seems to cast to match the right type itemsPtr needs. The (__bridge void *) seems to cast to a pointer of type void with __bridge used to bridge the obj-c world to the CF world. As per the llvm docs, for __bridge:
There is no transfer of ownership, and ARC inserts no retain operations
Is that correct?
From my understanding __NSCFConstantString is just the core foundation equivalent of NSString. I also understand that with ARC you need to bridge from Objective-C objects to CoreFoundation equivalents because ARC doesn't know how to manage the memory of the latter.
How can I get this working so that the objects in my 'for..in' loop are of the original type?
Also note that in this case I'm adding NSStrings to my collection but in theory it should support any object.
UPDATE
Rob's answer is on the right track, but to test that theory I changed the for loop to this:
for (id object in myCustomCollection) {
NSString *stringObject = (NSString *)object;
NSLog(#"String %# length: %d", stringObject, [stringObject length]);
}
In theory that should work since the objects are equivalent but it crashes with this error:
+[__NSCFConstantString length]: unrecognized selector sent to class
It almost looks like the objects returned in the for loop are classes and not instances. Something else might be wrong here... Any thoughts on this?
UPDATE 2 : SOLUTION
It's as simple as this: (thanks to CodaFi
state->itemsPtr = &someObject;
You're incorrectly casting someObject. What you meant is:
state->itemsPtr = (__unsafe_unretained id *)(__bridge void *)&someObject;
(Let's get rid of those awful casts as well)
state->itemsPtr = &someObject;
Without the address-of, your variable is shoved into the first pointer, which is dereferenced in the loop. When it's dereferenced (basically, *id), you get the underlying objc_object's isa class pointer rather than an object. That's why the debugger prints the string's value inside the enumerator call, and the class of the object inside the loop, and why sending a message to the resulting pointer throws an exception.
Your code is fine the way it is. Your debug output is revealing an implementation detail.
NSString is toll-free-bridged with CFString. This means that you can treat any NSString as a CFString, or vice versa, simply by casting the pointer to the other type.
In fact, under the hood, compile-time constant strings are instances of the type __NSCFConstantString, which is what you're seeing.
If you put #"hello" in your source code, the compiler treats it as a NSString * and compiles it into an instance of __NSCFConstantString.
If you put CFSTR("hello") in your source code, the compiler treats it as a CFStringRef and compiles it into an instance of __NSCFConstantString.
At run-time, there is no difference between these objects in memory, even though you used different syntax to create them in your source code.
In c++ i would do the following,
Object* obj1;
Object* obj2;
Object** targetObj;
void SetTargetToObj1()
{
targetObj = &obj1;
}
void SetTargetToObj2()
{
targetObj = &obj2;
}
void ValueChanged()
{
//So if SetTargetToObj2() was called before ValueChanged() we
// would be changing some data on obj2
(*targetObj)->ChangeSomeData();
//or, we obj2 is null we could assign a new object to it via targetObj
(*targetObject) = new Object();
//now obj2 is pointing to our new object
}
Im wondering if there is a way in obj-c to do this same thing with NSObjects?
Pointers to pointers are not so simple under ARC.
When you declare, say, an instance variable:
NSObject *someObject;
you are implicitly declaring:
NSObject * __strong someObject;
i.e. a strong pointer. Strong is just one of the ownership qualifiers, you can also have weak and autoreleasing qualifiers.
Now taking the example in your comment:
NSDate **targetDate;
you get the error "pointer to non-const type 'NSDate *' with no explicit ownership". This is because ARC needs to know the ownership qualification of the pointer your pointer is referring to (read it slowly! ;-)). i.e ARC is asking you to type the variable instead as:
NSData * 'some ownership qualifer' * targetDate;
which, once you've decoded C's type priority rules, is a "pointer to a 'some ownership qualifier' pointer to an NSDate".
The error message includes "non-const" as this is all about writing via your pointer to pointer - ARC still needs to know how to handle the store, which depends on whether the pointed at reference is strong, weak, etc.
In your simple case the following should do:
NSObject *obj1;
NSObject *obj2;
NSObject * __strong * targetObj;
and then when doing (*targetObj) = ... etc. ARC knows what to do for memory management - which in this case is to release the old value in the variable referenced by targetObj as well as assigning the new reference into that variable.
Essential reading is Automatic Reference Counting and Transitioning to ARC Release Notes - in particular look up NSError in the latter as it explains how the common pattern of declaring error parameters as NSError ** is handled under ARC.
The code you have right there is already fine. If Object is in fact an obj-c object then this exact code is what you want. The only quirk is potential memory management issues (e.g. does targetObj need to retain the thing it's pointing to?)
I was told by a fellow StackOverflow user that I should not use the getter method when releasing a property:
#property(nonatmic, retain) Type* variable;
#synthesize variable;
// wrong
[self.variable release];
// right
[variable release];
He did not explain in detail why. They appear the same to me. My iOS book said the getter on a property will look like this:
- (id)variable {
return variable;
}
So doesn't this mean [self variable], self.variable, and variable are all the same?
For a retained property with no custom accessor, you can release the object by:
self.variable = nil;
This has the effect of setting the ivar (which may not be called 'variable' if you have only declared properties) to nil and releasing the previous value.
As others have pointed out, either directly releasing the ivar (if available) or using the method above is OK - what you must not do is call release on the variable returned from a getter.
You can optionally write custom getter behavior, which may result in completely different behavior. So, you cannot always assume that [variable release] has the same results as [self.variable release].
As well, you can write custom properties without an exclusive ivar backing them... it can get messy fast if you start releasing objects from references returned by getters!
There may be additional reasons that I'm unaware of...
A typical getter will look more like this:
- (id)variable {
return [[variable retain] autorelease];
}
So if you use [self.variable release] you have an additional retain and autorelease that you don't really need when you just want to release the object and that cause the object to be released later than necessary (when the autorelease pool is drained).
Typically, you would either use self.variable = nil which has the benefit that it also sets the variable to nil (avoiding crashes due to dangling pointers), or [variable release] which is the fastest and may be more appropriate in a dealloc method if your setter has custom logic.
not all getters take this form:
- (id)variable { return variable; }
...that is merely the most primitive form. properties alone should suggest more combinations, which alter the implementation. the primitive accessor above does not account for idioms used in conjunction with memory management, atomicity, or copy semantics. the implementation is also fragile in subclass overrides.
some really brief examples follow; things obviously become more complex in real programs where implementations become considerably more complex.
1) the getter may not return the instance variable. one of several possibilities:
- (NSObject *)a { return [[a copy] autorelease]; }
2) the setter may not retain the instance variable. one of several possibilities:
- (void)setA:(NSObject *)arg
{
...
a = [arg copy];
...
}
3) you end up with memory management implementation throughout your program, which makes it difficult to maintain. the semantics of the class (and how it handles instance variables' ref counting) should be kept to the class, and follow conventions for expected results:
- (void)stuff:(NSString *)arg
{
const bool TheRightWay = false;
if (TheRightWay) {
NSMutableString * string = [arg mutableCopy];
[string appendString:#"2"];
self.a = string;
[string release];
// - or -
NSMutableString * string = [[arg mutableCopy] autorelase];
[string appendString:#"2"];
self.a = string;
}
else {
NSMutableString * string = [arg mutableCopy];
[string appendString:#"2"];
self.a = string;
[self.a release];
}
}
failing to follow these simple rules makes your code hard to maintain and debug and painful to extend.
so the short of it is that you want to make your program easy to maintain. calling release directly on a property requires you to know a lot of context of the inner workings of the class; that's obviously bad and misses strong ideals of good OOD.
it also expects the authors/subclassers/clients to know exactly how the class deviates from convention, which is silly and time consuming when issues arise and you have to relearn all the inner details when issues arise (they will at some point).
those are some trivial examples of how calling release on the result of a property introduces problems. many real world problems are much subtler and difficult to locate.