Automatic Reference Counting not working [duplicate] - ios

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why is object not dealloc'ed when using ARC + NSZombieEnabled
I must be doing something wrong here. Compiler is set to Apple LLVM Compiler 3.0 and Objective-C Automatic Reference Counting is set to YES. I also have 3rd Party Software included that requires ARC to be active.
So my basic problem is that my properties don't get released. I have the following header:
#interface ArchiveController : UIViewController <CloseSubviewDelegate> {
NSArray *journals;
NSMutableArray *archiveViews;
}
#property (nonatomic, strong) NSArray *journals;
#property (nonatomic, strong) NSMutableArray *archiveViews;
....
#end
I synthesized those and initialize the archiveViews array like this:
self.archiveViews = [NSMutableArray array];
later I add objects to it, everything works fine; same for the journals array.
I added a dealloc method to check that the ArchiveController gets released:
-(void)dealloc
{
DLog(#"dealloc archive controller");
}
which works, but the arrays are never released; Why? If I change the dealloc method to this:
-(void)dealloc
{
DLog(#"dealloc archive controller");
self.archiveViews = nil;
}
everything works fine, but thats not the way it should be, right? I'm a 100 % certain that the array and its objects aren't referenced anywhere else.
And isn't the Preprocessor supposed to handle the insertion of all the retains/releases/deallocs? when I let Xcode generate preprocessed output, nothing seems changed!

I suspect a circular dependency.
Instruments can help you locate them at times.

Related

Understanding why assign is breaking code in swift

I made an xcframework (in objective c) which is working fine in objective C but throws an error when using swift.
On debugging, I realized that it was breaking in swift because I was using assign.
I went through his answer: https://stackoverflow.com/a/4511004/10433835
where they say this
In most cases you'll want to use weak so you're not trying to access a deallocated object
I didn't quite get what assign does, but I don't think I am trying to access a deallocated object.
This is what I am doing
I have config with these properties
#import <Foundation/Foundation.h>
#interface Config : NSObject
#property(nonatomic, assign, readwrite) NSString *name;
#property(nonatomic, assign, readwrite) NSString *id;
#property(nonatomic, assign, readwrite) NSString *api;
#end
This is my Config.m file
#implementation Config
- (id)init {
if (self = [super init]) {
_api = #"https://api.xyz.in"
}
return self;
}
- (NSMutableDictionary *_Nonnull)configProperties {
if (!_name) {
[NSException raise:#"name" format:#"Room name cannot be null, please set room name"];
}
NSLog(#"Room name: %#", _name);
At this line it will throw Thread 1: EXC_BAD_ACCESS
NSLog(#" name: %#", _name);
if I remove assign, it won't throw any error
How am I calling it?
let config:Config = Config();
config.name = "varun_bindal";
let props = config.configProperties()
Can someone please explain me why using assign in swift is crashing my code? and why not using it doesn't.
You actually don't want a weak or assign set for that property. The object will be deallocated as soon as it is set. You want a strong reference because the object owns the property. weak will nil the pointer as soon as it's set. So checking the pointer will return nil. assign will keep the address of the pointer without keeping the actual memory set. Hence you're pointing to something that has been deallocated. ie: pointing to bad memory location. It's kind of a remnant of the old days really..
You can read here for more info on keywords:
https://exceptionshub.com/property-and-retain-assign-copy-nonatomic-in-objective-c.html
The answer is: It's complicated.
Swift takes care of object ownership for you. Your only responsibility is to create strong or weak variables to avoid retain cycles. When you stay in Swift, it takes care of everything else.
Life is more complicated in Objective-C, and more complicated still when you need to have Objective-C and Swift code interact.
In order for Swift and Objective-C to work correctly together, you have to declare the memory semantics of your Objective-C classes correctly.
When you declare an Objective-C property as assign, you're telling the compiler not to do any memory management on it. Your Swift code won't set up strong references, and won't be notified if the object has been deallocated. If the Objective-C code doesn't need it any more and releases it, and your Swift code tries to reference it, you will crash.
(As mentioned in comments, Objective-C's assign is equivalent to unowned in Swift.)
As Larme says, assign is ok for non-object scalar types, but not for objects.

How to create a new object and assign properties in Objective-C?

I'm trying to bridge an Objective C SDK with React Native and I'm having some trouble. I have a Subclass of NSObject and I'm trying to set some property values but I can't get it to work.
I have tried to change the property in the header, and in the imp file with out any difference.
PrinterSDK.h (which has libPrinterSDK.a)
#interface Printer : NSObject
#property (nonatomic, readonly) NSString* name;
#property (nonatomic, readonly) NSString* UUIDString;
#end
RNPosPrint.m
#interface Printer ()
#property (readwrite) NSString* name;
#property (readwrite) NSString* UUIDString;
#end
RCT_EXPORT_METHOD(printTestPaper:(NSString*)name:(NSString*)uuid)
{
Printer* printer = [[Printer alloc] init];
printer.name = name;
}
But I keep facing issue with the setter for some reason I can't figure out.
ExceptionsManager.js:94 Exception '-[Printer setPrinterName:]: unrecognized selector sent to instance 0x13fd25b90' was thrown while invoking printTestPaper on target RNPosPrint with params (
"Test Printer",
"XXX-XXX-XXX"
)
You do not report the names of your .h and .m files or what else is in the .m – e.g. #implementation of Printer? The class printTestPaper belongs to? Without details like this it is difficult for anyone to help you, you need to help people help you.
That said some points that may help you:
The #interface Printer () where you open up the properties to be writeable should be in the your Printer.m file – in general do not try to open up access to a type's properties from outside the type's implementation, it is both bad design and may not work as you hope (as you just found out).
The code to support a #property is generated by the compiler when it compiles the #implementation, #interface's themselves produce no executable code – they describe the accessible parts of the #implementation.
setter=<name> provides a different name for the auto-created property setter function. While a method <name> will be created to set the property using dot syntax the properties name is still used, e.g. in your case printer.name = ... is still used even with the setter=setPrinterName:. You can call the auto-created method using standard method syntax, that failed in your case for the reasons above.
Using setter=<name> or getter=<name> are really advanced features and you probably will never need to use them – when you do need to use them you will know! Just avoid them till then.
If you wish to provide a method which creates the object and sets properties then do this in the type's implementation. The usual way of doing this is to provide an init method that does this, e.g. in this case it might be - initWithName:(NSString *)printerName { ... }, or an equivalent class method which does the allocation and sets the parameters, e.g. in this case it might be + newWithName:(NSString *)printerName { ... }.
HTH
Since it's an interface from statically linked library it is simply not possible to extend or manipulate. Not without tempering with the compiler.

I have a about iOS Block modifiers and scopes and need help. Description show in full code

I did the experiment as shown in the figure, but I couldn't understand the result.
This is my full code:
#import "ViewController.h"
#interface ViewController ()
#property(nonatomic,strong) void (^DemoBlock4)(void);
#property(nonatomic,copy) void (^DemoBlock5)(void);
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Now is MRC, The copy shoudn't Automatic.
int a = 6;
// //__NSStackBlock__
void (^DemoBlock2)(void) = ^{
NSLog(#"DemoBlock2 %d",a);
};
NSLog(#"DemoBlock2 %#",DemoBlock2);
//__NSMallocBlock__
// This is I executed it manually 'copy',[DemoBlock2 copy] is exactly the same as DemoBLock3
NSLog(#"DemoBlock2.Copy %#",[DemoBlock2 copy]);
void (^DemoBLock3)(void) = [DemoBlock2 copy];
NSLog(#"DemoBlock3 %#",DemoBLock3);
//But why self.DemoBlock4 is same __NSMallocBlock__? And I used the 'strong' modifier.
//self.DemoBlock4 log is exactly the same as self.DemoBlock5(I user 'copy'),
self.DemoBlock4 = ^{
NSLog(#"%d",a);
};
NSLog(#"DemoBlock4 %#",self.DemoBlock4);
self.DemoBlock5 = ^{
NSLog(#"%d",a);
};
NSLog(#"DemoBlock5 %#",self.DemoBlock5);
}
This is Log:
2018-11-30 13:02:35.170860+0800 blocktest[73540:8352045] DemoBlock2 <__NSStackBlock__: 0x7ffeea3b89f8>
2018-11-30 13:02:35.170994+0800 blocktest[73540:8352045] DemoBlock2.Copy <__NSMallocBlock__: 0x60c00005eba0>
2018-11-30 13:02:35.171102+0800 blocktest[73540:8352045] DemoBlock3 <__NSMallocBlock__: 0x60800004ec70>
2018-11-30 13:02:35.171215+0800 blocktest[73540:8352045] DemoBlock4 <__NSMallocBlock__: 0x60c00005f680>
2018-11-30 13:02:35.171320+0800 blocktest[73540:8352045] DemoBlock5 <__NSMallocBlock__: 0x60c00005f0e0>
So, as property copy(like [DemoBlock2 copy]) is automatic, even MRC?
And that makes copy and stronglook the same.
I've read a lot about it and learned that Apple recommends using copy,
But I'd want to know more about what happens when different modifiers are used as property.
So I wrote this Dome.
Like this:
#interface XYZObject : NSObject
#property (copy) void (^blockProperty)(void);
#end
-fno-objc-arc ViewController
Regarding strong vs copy semantics for block properties, you should use copy semantics (and in ARC, this happens automatically). See Programming with Objective-C: Working with Blocks, which says:
Objects Use Properties to Keep Track of Blocks
The syntax to define a property to keep track of a block is similar to a block variable:
#interface XYZObject : NSObject
#property (copy) void (^blockProperty)(void);
#end
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.
I can't find a very clear explanation of the semantics of the ARC modifier strong when used for properties in MRC, but it seems that in Clang, strong for properties in MRC means a retaining setter if the property has non-block type, and a copying setter if the property has block type. I found the commit in 2011 in Clang that implemented this behavior.
So that's why your DemoBlock4 is copied -- the property is a strong property of block type, for which Clang produces a synthesized setter that copies the block.
(Note that this is different from retain, which always means a retaining setter even if the property is block type. So if you change DemoBlock4 from strong to retain, you will see that it prints __NSStackBlock__ instead; and the compiler gives you a warning.)

is alloc not available for my object?

I created a few custom objects, where one holds a container of the other.
The interface for ClassObject has a publicly declared init function like this:
#interface ClassObject : NSObject
#property NSDate *earliestDate;
#property NSDate *latestDate;
- (id) initWithHKQuantitySample: (HKQuantitySample *)sample;
#end
So I'd like to do the following:
ClassObject * newObject = [[ClassObject alloc] initWithClass2Object:sample];
However, I am being stopped because Xcode is not recognizing alloc as a valid selector and is only suggested alloca(size_t), which is most definitely not what I want.
What am I doing wrong?
This seems like such a basic thing, I can't figure out what I am missing or have forgotten.
Thanks for any suggestions!
If you haven't imported the header file for your custom class, it won't be recognized by Xcode. Wherever you want to use ClassObject, you should make sure you have this:
#import "ClassObject.h"
Other than that, your class looks fine to me.

EXC_BAD_ACCESS using ARC only during testing

I have an issue where I'm getting bad access exceptions but only when running a testing build (calling the same methods in a debug build doesn't cause the problem to come up). The project has ARC enabled and I'm running this on the iPad 5.1 simulator using Xcode 4.3:
Here's where the problem crops up:
- (void)testChangeFoodNotification {
Player* p = [[Player alloc] init];
[p addObserver:self forKeyPath:#"food" options:0 context:0]; // <-EXC_BAD_ACCESS (code=2)
p.food += 1;
STAssertTrue(_wasNotifiedOfFoodChange, nil);
}
At the point when the addObserver: method is called it doesn't seem like any of the objects involved should have been released so what could be causing the exception?
EDIT:
Apologies if it wasn't clear but the code above is being executed as part of a test case (using the standard Xcode OCUnit). Also in case it clarifies anything here's the relevant code from the player class (there's other ivars and methods but they don't have any connection to the property or methods being tested):
// Public interface
#interface Player : NSObject
#property (nonatomic, assign) NSInteger food;
#end
// Private interface
#interface Player() {
NSInteger _food;
}
#end
#implementation Player
#synthesize food = _food;
#pragma mark - Getters/Setters
- (void)setFood:(NSInteger)food {
[self willChangeValueForKey:#"food"];
_food = food;
[self didChangeValueForKey:#"food"];
}
If your class is indeed key-value compliant, ensure that the implementation for the class exhibiting the issue is not included in your test product. This means that the Target Membership panel of the Identity inspector for your .m file should only have your app checked (not YourAppTests).
I experienced the same issue in Xcode 4.3.1 when an implementation was included in both products and I registered observers in both production and test code. The following logs tipped me off:
Class YourClass is implemented in both /Users/yourUser/Library/Application Support/iPhone Simulator/5.1/Applications//YourApp.app/YourApp and /Users/yourUser/Library/Developer/Xcode/DerivedData/YourApp-/Build/Products/Debug-iphonesimulator/YourAppTests.octest/YourAppTests. One of the two will be used. Which one is undefined.
As per the Key-Value Observing Programming Guide, is your Player key-value-compliant? You want to make sure you are Ensuring KVC Compliance. I also assume that you have also implemented your observeValueForKeyPath:ofObject:change:context:? If you think you've done all of this and it's still not working, then perhaps you can share your code.
Also, minor thing, but I assume this is a code snippet to highlight the issue. I only mention it because ARC is going to be releasing your p object at the end of your testChangeFoodNotification and I would have thought that you'd want to remove your observer first.

Resources