Can I have a static pointer that is weak in objective-c? I know it compiles, but I want to know if it will behave as I expect a weak pointer to behave.
__weak static HMFSomeClass *weakStaticPointer;
Yes, that behaves like a proper weak pointer:
__weak static NSObject *weakStaticPointer;
int main(int argc, char * argv[])
{
#autoreleasepool {
NSObject *obj = [NSObject new];
weakStaticPointer = obj;
NSLog(#"%#", weakStaticPointer);
obj = nil; // object is deallocated -> weak pointer is set to nil
NSLog(#"%#", weakStaticPointer);
}
return 0;
}
Output:
<NSObject: 0x100106a50>
(null)
Also I cannot find any restrictions in the Clang/ARC documentation that forbids
a weak pointer to be static.
Related
I want to directly assign value to an ivar of class concurrently.
I know there will be problem using setter method (self.target = ...) since ARC inner retain and release stuff for strong property. But I'm trying to use ivar.
Is it because the implicit qualifier __strong? But _target is an ivar, so it won't be released outside each dispatch_async block, right?
And if you make the string shorter, iOS system will apply a tagged pointer to _target, why in this case no bad access error happens anymore?
#interface ClassA ()
#property (nonatomic, strong) NSString *target;
#end
#implementation ClassA
- (void)test {
dispatch_queue_t queue = dispatch_queue_create("parallel", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 10000 ; i++) {
dispatch_async(queue, ^{
_target = [NSString stringWithFormat:#"aaaaaaaaaaaaaa-%d",i]; //Bad Access Error in releasing, an NSCFString
//_target = [NSString stringWithFormat:#"aa-%d",i]; //No problem, an NSTaggedPointerString
});
}
}
#end
int main(int argc, char * argv[]) {
ClassA *obj = [[ClassA alloc] init];
[obj test];
return 0;
}
Using ivar doesn't makes difference: compiler just add retain/release instead of you. You need unsafe_unretained property to disable insertion of retain/release
#interface Soka : NSObject
#property (nonatomic, copy) NSString * name;
-(void)speak;
#end
#implementation Soka
-(void)speak{
NSLog(#"my name is: %#", self.name);
}
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSString * asdfasdfasdfsdf = #"xxxxxxx4";
id cls = [Soka class];
void * obj = &cls;
[(__bridge id)obj speak];
}
return 0;
}
The output is :
[14402:5468392] my name is: xxxxxxx4
Can anyone explain this??
How was the asdfasdfasdfsdf values set to class property?
Thanks
Thanks for all your guys' replies:
Making An Update:
#Leo
Thanks for your reply.
1# What is the meaning of Soka Class object cls, what is its memory structure. It's pointer pointing to what address?
2# find memory near the ocObj object? what if the nearest memory is an integer value? It's a part of OBJC or whatelse theory?
Well it is a little tricky,not useful. It is about Objective C instance memory
Your code can be converted to this
NSString * asdfasdfasdfsdf = #"xxxxxxx4";
Class cls = [Soka class];
void * obj = &cls;
id ocObj = (__bridge id)obj;
NSLog(#"%#",[ocObj name]);
Lets make it clear one by one
cls is a Soka Class object
Class cls = [Soka class];
obj is a pointer point to Soka Class object
void * obj = &cls;
This convert obj to Object C object
id ocObj = (__bridge id)obj;
When call this [ocObj name],Objective C will find memory near the ocObj object.It is #"xxxxxxx4" in the stack.
Also,I test this to make sure I am right
#interface Soka : NSObject
#property (nonatomic, copy) NSString * name;
#property (nonatomic,copy) NSString * address;
-(void)speak;
#end
#implementation Soka
-(void)speak{
NSLog(#"my name is: %#", self.name);
}
#end
int main(int argc, char * argv[]) {
#autoreleasepool {
NSString * asdfasdfasdfsdf = #"xxxxxxx4";
NSString * address = #"address";
Class cls = [Soka class];
void * obj = &cls;
id ocObj = (__bridge id)obj;
NSLog(#"%#",[ocObj name]);
NSLog(#"%#",[ocObj address]);
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
This will log
2015-07-01 23:26:56.857 OCTest[10910:347815] address
2015-07-01 23:26:56.859 OCTest[10910:347815] xxxxxxx4
Update:
+class function will return the class object of one class and type is Class.
So,what is Class type,it is something about objective c runtime
typedef struct objc_class *Class;
This is the define of objc_class
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
When you create an Objective C object,it will auto manage the memory. In your code,it is just a trick to make an Objective C object like memory.
Actually objective-c's classes is structures with properties.
For your's class Soka you have hidden fields in that structure: _name and class. They placed in same order, as placed your's variables asdfasdfasdfsdf and cls.
All works fine because at address &cls placed variable of type Class, that describes class. So after casting obj to id runtime find required field, that describes class and trust that that pointer points at Soka. Of course it'f false, but by circumstances that variables placed at same order and at right places this code work and doesn't crush.
You can't alloc objective-c objects in stack and should avoid this code if you think that you can alloc objective-c object in such way. Because it can lead to unpredicted errors.
The class method gives you the type of an object.
For example, if you want to know if myObject is an NSString, you could do this:
[myObject isKindOfClass:[NSString class]]
isKindOfClass takes a type as its argument, so we call class on NSString to get the type.
It's like typeof in the C languages.
This question already has answers here:
Why isn’t my weak reference cleared right after the strong ones are gone?
(4 answers)
Closed 9 years ago.
In the following code, which is ARC'd and running 64-bit on Mac OS X 10.8.4, why is the instance of MyObj not being deallocated before the program terminates?
#import <Foundation/Foundation.h>
#interface MyObj : NSObject
#end
#implementation MyObj
- (void)dealloc
{
NSLog(#"MyObj dealloc'd %p", self);
}
#end
int main(int argc, const char * argv[])
{
MyObj* obj1 = [[MyObj alloc] init];
__weak MyObj* weakObj1 = obj1;
NSLog(#"Use it: %p\n", weakObj1);
// Why isn't MyObj deallocated here?
return 0;
}
__weak relies on the Objective-C runtime function objc_loadWeak. From Objective-C Automatic Reference Counting in the documentation for Clang 3.4:
id objc_loadWeak(id *object);
Precondition: object is a valid pointer which either contains a null
pointer or has been registered as a __weak object.
If object is registered as a __weak object, and the last value stored
into object has not yet been deallocated or begun deallocation,
retains and autoreleases that value and returns it. Otherwise returns
null. Equivalent to the following code:
id objc_loadWeak(id *object) {
return objc_autorelease(objc_loadWeakRetained(object));
}
Must be atomic with respect to calls to objc_storeWeak on object.
Rationale
Loading weak references would be inherently prone to race
conditions without the retain.
Since objc_loadWeak requires an autorelease pool, then you must have an autorelease pool present when using __weak. The pool can created by either NSAutoreleasePool or #autoreleasepool. If an autorelease pool is not present, then nothing will release your object after objc_loadWeak retains it and your object will therefore never be deallocated.
Here is a fix for the code above:
#import <Foundation/Foundation.h>
#interface MyObj : NSObject
#end
#implementation MyObj
- (void)dealloc
{
NSLog(#"MyObj dealloc'd %p", self);
}
#end
int main(int argc, const char * argv[])
{
#autoreleasepool {
MyObj* obj1 = [[MyObj alloc] init];
__weak MyObj* weakObj1 = obj1;
NSLog(#"Use it: %p\n", weakObj1);
// Now MyObj is deallocated
}
return 0;
}
weakObj1 is not going to be deallocated until main ends. When you are using ARC, which is what you should do, variables and objects won't be deallocated until the block where they were declared in ends. When this happens, all the objects that are not being strong referenced by any object will be deallocated.
Keep on mind that to deallocate an object a release message has to be sent to it. If you are using manual retain-release, MRR, you have to do it by yourself, if you are using automatic reference counting, ARC, the system will do it for you.
I have a C (Objective-C) structure defined:
struct ResultadoVentaPUP{
NSString *autenticadoPorPin1;
NSString *autenticadoPorPin2;
NSString *tipoPago;
NSString *importe;
};
Then I declare a variable of this type globally (at top of the file):
ResultadoVentaPUP resven;
In a function I set values for this structure, for example:
resven.importe=#"12.45";
but when I try to view the content of "importe" in another function from the same file), ir returns (null).
NSLog(#"Result: %#",resven.importe);
What am I doing wrong? should I define the struct with 'static'?
Thank you!
Storing Obj-C objects in a C structure is a rather bad idea nowadays anyway, with ARC (Automatic Reference Counting), it is not even allowed any longer (the compiler will complain if you do that). Why not using an object instead? If you don't want to use assessor methods because you fear the overhead, just use an object with public ivars. Public ivars are bad IMHO, yet a struct is pretty much the same as an object with public ivars.
#interface ResultadoVentaPUP : NSObject
{
#public
NSString * autenticadoPorPin1;
NSString * autenticadoPorPin2;
NSString * tipoPago;
NSString * importe;
}
#end
#implementation ResultadoVentaPUP
#end
ResultadoVentaPUP * resven;
void someFunction () {
resven = [[ResultadoVentaPUP alloc] init];
resven->importe = #"12.45";
}
void someOtherFunction () {
NSLog(#"Result: %#",resven->importe);
}
This code will also work nicely if you use ARC and sooner or later every project should migrate to ARC in the near future (as soon as it can drop support for OSX/iOS versions without ARC support).
Maybe your declaration should be struct ResultadoVentaPUP resven;. This works for me:
#import <Foundation/Foundation.h>
struct ResultadoVentaPUP{
NSString *autenticadoPorPin1;
NSString *autenticadoPorPin2;
NSString *tipoPago;
NSString *importe;
};
struct ResultadoVentaPUP resven;
void func1() {
resven.importe = #"12.45";
}
void func2() {
NSLog(#"Result: %#", resven.importe);
}
int main(int argc, char *argv[]) {
NSAutoreleasePool *p = [[NSAutoreleasePool alloc] init];
func1();
func2();
[p release];
}
And I would be remiss if I didn't include the caveat that any time you are using global variables you should seriously be reconsidering your design.
I need to store weak references to objects in an NSArray, in order to prevent retain cycles. I'm not sure of the proper syntax to use. Is this the correct way?
Foo* foo1 = [[Foo alloc] init];
Foo* foo2 = [[Foo alloc] init];
__unsafe_unretained Foo* weakFoo1 = foo1;
__unsafe_unretained Foo* weakFoo2 = foo2;
NSArray* someArray = [NSArray arrayWithObjects:weakFoo1, weakFoo2, nil];
Note that I need to support iOS 4.x, thus the __unsafe_unretained instead of __weak.
EDIT (2015-02-18):
For those wanting to use true __weak pointers (not __unsafe_unretained), please check out this question instead: Collections of zeroing weak references under ARC
As Jason said, you can't make NSArray store weak references. The easiest way to implement Emile's suggestion of wrapping an object inside another object that stores a weak reference to it is the following:
NSValue *value = [NSValue valueWithNonretainedObject:myObj];
[array addObject:value];
Another option: a category that makes NSMutableArray optionally store weak references.
Note that these are "unsafe unretained" references, not self-zeroing weak references. If the array is still around after the objects are deallocated, you'll have a bunch of junk pointers.
The solutions to use a NSValue helper or to create a collection (array, set, dict) object and disable its Retain/Release callbacks are both not 100% failsafe solutions with regard to using ARC.
As various comments to these suggestions point out, such object references will not work like true weak refs:
A "proper" weak property, as supported by ARC, has two behaviors:
Doesn't hold a strong ref to the target object. That means that if the object has no strong references pointing to it, the object will be deallocated.
If the ref'd object is deallocated, the weak reference will become nil.
Now, while the above solutions will comply with behavior #1, they do not exhibit #2.
To get behavior #2 as well, you have to declare your own helper class. It has just one weak property for holding your reference. You then add this helper object to the collection.
Oh, and one more thing: iOS6 and OSX 10.8 supposedly offer a better solution:
[NSHashTable weakObjectsHashTable]
[NSPointerArray weakObjectsPointerArray]
[NSPointerArray pointerArrayWithOptions:]
These should give you containers that hold weak references (but note matt's comments below).
An example (updated 2 Feb 2022)
#import <Foundation/Foundation.h>
static BOOL didDealloc = NO;
#interface TestClass : NSObject
#end
#implementation TestClass
-(void)dealloc {
didDealloc = YES;
}
#end
int main(int argc, const char * argv[]) {
NSPointerArray *pa = [NSPointerArray weakObjectsPointerArray];
#autoreleasepool {
TestClass *obj = TestClass.new;
[pa addPointer:(__bridge void * _Nullable)(obj)]; // stores obj as a weak ref
assert([pa pointerAtIndex:0] != nil);
assert(!didDealloc);
} // at this point the TestClass obj will be deallocated
assert(didDealloc);
assert([pa pointerAtIndex:0] == nil); // verify that the weak ref is null now
return 0;
}
If you run this you'll find that after adding the TestClass object to the pointer array pa, then releasing that object again, the pointer (which is internally a weak object ref) is now set to null as desired.
However, note that calling [pa compact] at the end will not remove the nil pointer as I'd have expected.
I am new to objective-C, after 20 years of writing c++.
In my view, objective-C is excellent at loosely-coupled messaging, but horrible for data management.
Imagine how happy I was to discover that xcode 4.3 supports objective-c++!
So now I rename all my .m files to .mm (compiles as objective-c++) and use c++ standard containers for data management.
Thus the "array of weak pointers" problem becomes a std::vector of __weak object pointers:
#include <vector>
#interface Thing : NSObject
#end
// declare my vector
std::vector<__weak Thing*> myThings;
// store a weak reference in it
Thing* t = [Thing new];
myThings.push_back(t);
// ... some time later ...
for(auto weak : myThings) {
Thing* strong = weak; // safely lock the weak pointer
if (strong) {
// use the locked pointer
}
}
Which is equivalent to the c++ idiom:
std::vector< std::weak_ptr<CppThing> > myCppThings;
std::shared_ptr<CppThing> p = std::make_shared<CppThing>();
myCppThings.push_back(p);
// ... some time later ...
for(auto weak : myCppThings) {
auto strong = weak.lock(); // safety is enforced in c++, you can't dereference a weak_ptr
if (strong) {
// use the locked pointer
}
}
Proof of concept (in the light of Tommy's concerns about vector reallocation):
main.mm:
#include <vector>
#import <Foundation/Foundation.h>
#interface Thing : NSObject
#end
#implementation Thing
#end
extern void foo(Thing*);
int main()
{
// declare my vector
std::vector<__weak Thing*> myThings;
// store a weak reference in it while causing reallocations
Thing* t = [[Thing alloc]init];
for (int i = 0 ; i < 100000 ; ++i) {
myThings.push_back(t);
}
// ... some time later ...
foo(myThings[5000]);
t = nullptr;
foo(myThings[5000]);
}
void foo(Thing*p)
{
NSLog(#"%#", [p className]);
}
example log output:
2016-09-21 18:11:13.150 foo2[42745:5048189] Thing
2016-09-21 18:11:13.152 foo2[42745:5048189] (null)
If you do not require a specific order you could use NSMapTable with special key/value options
NSPointerFunctionsWeakMemory
Uses weak read and write barriers appropriate for ARC or GC. Using NSPointerFunctionsWeakMemory object references will turn to NULL on last release.
I believe the best solution for this is to use NSHashTable or NSMapTable. the Key or/and the Value can be weak. You can read more about it here: http://nshipster.com/nshashtable-and-nsmaptable/
To add weak self reference to NSMutableArray, create a custom class with a weak property as given below.
NSMutableArray *array = [NSMutableArray new];
Step 1: create a custom class
#interface DelegateRef : NSObject
#property(nonatomic, weak)id delegateWeakReference;
#end
Step 2: create a method to add self as weak reference to NSMutableArray. But here we add the DelegateRef object
-(void)addWeakRef:(id)ref
{
DelegateRef *delRef = [DelegateRef new];
[delRef setDelegateWeakReference:ref]
[array addObject:delRef];
}
Step 3: later on, if the property delegateWeakReference == nil, the object can be removed from the array
The property will be nil, and the references will be deallocated at proper time independent of this array references
The simplest solution:
NSMutableArray *array = (__bridge_transfer NSMutableArray *)CFArrayCreateMutable(nil, 0, nil);
NSMutableDictionary *dictionary = (__bridge_transfer NSMutableDictionary *)CFDictionaryCreateMutable(nil, 0, nil, nil);
NSMutableSet *set = (__bridge_transfer NSMutableSet *)CFSetCreateMutable(nil, 0, nil);
Note: And this works on iOS 4.x too.
No, that's not correct. Those aren't actually weak references. You can't really store weak references in an array right now. You need to have a mutable array and remove the references when you're done with them or remove the whole array when you're done with it, or roll your own data structure that supports it.
Hopefully this is something that they'll address in the near future (a weak version of NSArray).
I've just faced with same problem and found that my before-ARC solution works after converting with ARC as designed.
// function allocates mutable set which doesn't retain references.
NSMutableSet* AllocNotRetainedMutableSet() {
CFMutableSetRef setRef = NULL;
CFSetCallBacks notRetainedCallbacks = kCFTypeSetCallBacks;
notRetainedCallbacks.retain = NULL;
notRetainedCallbacks.release = NULL;
setRef = CFSetCreateMutable(kCFAllocatorDefault,
0,
¬RetainedCallbacks);
return (__bridge NSMutableSet *)setRef;
}
// test object for debug deallocation
#interface TestObj : NSObject
#end
#implementation TestObj
- (id)init {
self = [super init];
NSLog(#"%# constructed", self);
return self;
}
- (void)dealloc {
NSLog(#"%# deallocated", self);
}
#end
#interface MainViewController () {
NSMutableSet *weakedSet;
NSMutableSet *usualSet;
}
#end
#implementation MainViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
weakedSet = AllocNotRetainedMutableSet();
usualSet = [NSMutableSet new];
}
return self;
}
- (IBAction)addObject:(id)sender {
TestObj *obj = [TestObj new];
[weakedSet addObject:obj]; // store unsafe unretained ref
[usualSet addObject:obj]; // store strong ref
NSLog(#"%# addet to set", obj);
obj = nil;
if ([usualSet count] == 3) {
[usualSet removeAllObjects]; // deallocate all objects and get old fashioned crash, as it was required.
[weakedSet enumerateObjectsUsingBlock:^(TestObj *invalidObj, BOOL *stop) {
NSLog(#"%# must crash here", invalidObj);
}];
}
}
#end
Output:
2013-06-30 00:59:10.266 not_retained_collection_test[28997:907]
constructed 2013-06-30 00:59:10.267
not_retained_collection_test[28997:907] addet to
set 2013-06-30 00:59:10.581 not_retained_collection_test[28997:907]
constructed 2013-06-30 00:59:10.582
not_retained_collection_test[28997:907] addet to
set 2013-06-30 00:59:10.881 not_retained_collection_test[28997:907]
constructed 2013-06-30 00:59:10.882
not_retained_collection_test[28997:907] addet to
set 2013-06-30 00:59:10.883 not_retained_collection_test[28997:907]
deallocated 2013-06-30 00:59:10.883
not_retained_collection_test[28997:907]
deallocated 2013-06-30 00:59:10.884
not_retained_collection_test[28997:907]
deallocated 2013-06-30 00:59:10.885
not_retained_collection_test[28997:907] * -[TestObj
respondsToSelector:]: message sent to deallocated instance 0x1f03c8c0
Checked with iOS versions 4.3, 5.1, 6.2.
Hope it will be useful to somebody.
If you need zeroing weak references, see this answer for code you can use for a wrapper class.
Other answers to that question suggest a block-based wrapper, and ways to automatically remove zeroed elements from the collection.
If you use a lot this comportment it's indicated to your own NSMutableArray class (subclass of NSMutableArray) which doesn't increase the retain count.
You should have something like this:
-(void)addObject:(NSObject *)object {
[self.collection addObject:[NSValue valueWithNonretainedObject:object]];
}
-(NSObject*) getObject:(NSUInteger)index {
NSValue *value = [self.collection objectAtIndex:index];
if (value.nonretainedObjectValue != nil) {
return value.nonretainedObjectValue;
}
//it's nice to clean the array if the referenced object was deallocated
[self.collection removeObjectAtIndex:index];
return nil;
}
I think an elegant solution is what Mr. Erik Ralston propose on his Github repository
https://gist.github.com/eralston/8010285
this are the essential steps:
create a category for NSArray and NSMutableArray
in the implementation create a convenience class with a weak property. Your category will assign the objects to this weak property.
.h
#import <Foundation/Foundation.h>
#interface NSArray(WeakArray)
- (__weak id)weakObjectForIndex:(NSUInteger)index;
-(id<NSFastEnumeration>)weakObjectsEnumerator;
#end
#interface NSMutableArray (FRSWeakArray)
-(void)addWeakObject:(id)object;
-(void)removeWeakObject:(id)object;
-(void)cleanWeakObjects;
#end
.m
#import "NSArray+WeakArray.h"
#interface WAArrayWeakPointer : NSObject
#property (nonatomic, weak) NSObject *object;
#end
#implementation WAArrayWeakPointer
#end
#implementation NSArray (WeakArray)
-(__weak id)weakObjectForIndex:(NSUInteger)index
{
WAArrayWeakPointer *ptr = [self objectAtIndex:index];
return ptr.object;
}
-(WAArrayWeakPointer *)weakPointerForObject:(id)object
{
for (WAArrayWeakPointer *ptr in self) {
if(ptr) {
if(ptr.object == object) {
return ptr;
}
}
}
return nil;
}
-(id<NSFastEnumeration>)weakObjectsEnumerator
{
NSMutableArray *enumerator = [[NSMutableArray alloc] init];
for (WAArrayWeakPointer *ptr in self) {
if(ptr && ptr.object) {
[enumerator addObject:ptr.object];
}
}
return enumerator;
}
#end
#implementation NSMutableArray (FRSWeakArray)
-(void)addWeakObject:(id)object
{
if(!object)
return;
WAArrayWeakPointer *ptr = [[WAArrayWeakPointer alloc] init];
ptr.object = object;
[self addObject:ptr];
[self cleanWeakObjects];
}
-(void)removeWeakObject:(id)object
{
if(!object)
return;
WAArrayWeakPointer *ptr = [self weakPointerForObject:object];
if(ptr) {
[self removeObject:ptr];
[self cleanWeakObjects];
}
}
-(void)cleanWeakObjects
{
NSMutableArray *toBeRemoved = [[NSMutableArray alloc] init];
for (WAArrayWeakPointer *ptr in self) {
if(ptr && !ptr.object) {
[toBeRemoved addObject:ptr];
}
}
for(WAArrayWeakPointer *ptr in toBeRemoved) {
[self removeObject:ptr];
}
}
#end