With ARC , why the dealloc not called - objective-c

I have enable the ARC. but this code makes me wonder
#interface Dog : NSObject
#end
#implementation Dog
- (void)dealloc
{
printf("Dog is dealloc\n"); //the function not called
}
#end
#interface Person : NSObject
#property (nonatomic, strong) Dog *dog;
#end
#implementation Person
- (void)dealloc
{
printf("Person is dealloc\n");
_dog = nil;
}
-(Dog *)dog
{
return _dog;
}
#end
int main()
{
Person *p = [[Person alloc] init];
p.dog = [[Dog alloc]init];
Dog* d = p.dog;
d=nil;
p=nil;
printf("end\n");
return 0;
}
the result is
Person is dealloc
end
Program ended with exit code: 0
why the dog's dealloc method not called.
and then I commented out this Method, the dog's dealloc method called.
//-(Dog *)dog
//{
// return _dog;
//}
thank you very much.

You can see the memory graph to find out what exactly points to the Dog and preserve it from automatically deallocation:
Unlike Swift, In Objective-C, you need to put the main body inside an #autoreleasepool to make it ARC compatible:
int main(int argc, const char * argv[]) {
#autoreleasepool {
// insert code here...
NSLog(#"Hello, World!");
Person *p = [[Person alloc] init];
p.dog = [[Dog alloc]init];
Dog* d = p.dog;
d = nil;
p = nil;
printf("Ended...\n");
}
return 0;
}
Then you will see this in the output:
Person is dealloc
Ended...
Dog is dealloc

Related

Why weak property of associated object is not nilled out if I call its getter?

Though it's kind of stupid in 2020 that I'm still asking question about ObjC, please be patient and considerate...
I'm reading the source code of BloksKit and ran into a weird situation.
#import <objc/runtime.h>
#interface _WeakAssociatedObjectWrapper : NSObject
#property (nonatomic, weak) id object;
#end
#implementation _WeakAssociatedObjectWrapper
#end
#interface NSObject (AddWeak)
#end
#implementation NSObject (AddWeak)
- (void)setWeakProp:(id)weakProp {
_WeakAssociatedObjectWrapper *wrapper = objc_getAssociatedObject(self, #selector(weakProp));
if (!wrapper) {
wrapper = [[_WeakAssociatedObjectWrapper alloc] init];
objc_setAssociatedObject(self, #selector(weakProp), wrapper, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
wrapper.object = weakProp;
}
- (id)weakProp {
id value = objc_getAssociatedObject(self, _cmd);
if ([value isKindOfClass:_WeakAssociatedObjectWrapper.class]) {
return [(_WeakAssociatedObjectWrapper *)value object];
}
return value;
}
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSObject *obj = [[NSObject alloc] init];
{
NSObject *prop = [[NSObject alloc] init];
[obj setWeakProp:prop];
[obj weakProp]; // *Weird!!
}
NSLog(#"Now obj.weakProp = %#", [obj weakProp]);
}
return 0;
}
This code is adding a weak associated object for category.(BlocksKit does so)
Note the *Weird!! line. If this line is commented out, then it prints (null), which is reasonable since prop is deallocated outside the {} scope. On the other side, if not commented out, it prints <NSObject: 0xxxxx>, which indicates that prop is somehow retained by someone(Or any other reason?).
What is happening here??! (BlocksKit behaves the same!)
Environment: XCode 10.3
This is a feature. For the case (and any similar)
[obj weakProp];
by properties/accessors naming convention ARC returns autoreleased instance, so in your case #autoreleasepool holds it and testing as below can show this.
int main(int argc, const char * argv[]) {
NSObject *obj = [[NSObject alloc] init];
#autoreleasepool {
{
NSObject *prop = [[NSObject alloc] init];
[obj setWeakProp:prop];
[obj weakProp]; // *Weird!!
}
NSLog(#"Now obj.weakProp = %#", [obj weakProp]);
}
NSLog(#"After autoreleased >> obj.weakProp = %#", [obj weakProp]);
return 0;
}

How does the Xcode breakpoint system interact with memory management?

Here's a little experiment:
#interface Model : NSObject
#property (copy) NSString *value;
-(instancetype)initWith:(NSString *)value;
#end
#implementation Model
-(instancetype)initWith:(NSString *)value {
self = [super init];
self.value = value;
return self;
}
#end
#import <Foundation/Foundation.h>
#import "Model.h"
void experiment(Model *m);
int main(int argc, const char * argv[]) {
#autoreleasepool {
// insert code here...
NSLog(#"Hello, World!");
Model *ma = [[Model alloc] initWith:[[NSUUID UUID] UUIDString]];
experiment(ma);
NSLog(#"yyy %#", [ma value]);
}
return 0;
}
void experiment(ModelA *m) {
NSString *testValue = nil;
testValue = [m value];
NSLog(#"xxx %#", testValue);
}
When run, this produces the following:
Hello, World!
xxx 6005A7B0-F71C-4755-B1BF-792D6296B716
yyy 6005A7B0-F71C-4755-B1BF-792D6296B716
Program ended with exit code: 0
But suppose I make this line:
testValue = [m value];
part of a breakpoint:
And this changes everything:
Hello, World!
(__NSCFString *) $0 = 0x000000010071e220 #"1C0DCB39-BFBB-4E67-A041-E6B58615BDFD"
xxx 1C0DCB39-BFBB-4E67-A041-E6B58615BDFD
yyy 1C0DCB39-BFBB-4E67-A041-E6B58615BDFD
*** -[CFString release]: message sent to deallocated instance 0x10071e220
And a crash. I see what's happening--the string is released once we exit the function scope, and the second time when the Model object is destroyed, which is an overrelease. But why doesn't the breakpoint (or more precisely, the lldb expression inside the breakpoint) handle the reference count correctly?

Set readonly attribute in ObjC

Is there a way to set a value to readonly attribute in Objective-C?
I actually don't care how nasty the code is unless it isn't stable anymore.
Never mind my comment, here's the two ways you do it:
#interface Grimley : NSObject
#property (readonly, copy) NSString * blabber;
#property (readonly, copy) NSString * narwhal;
- (id) initWithBlabber:(NSString *)newBlabber;
#end
#implementation Grimley
#synthesize blabber;
#synthesize narwhal = unicorn;
- (id) initWithBlabber:(NSString *)newBlabber {
self = [super init];
if( !self ) return nil;
// Any object can of course set its own ivar regardless
// of how the property it backs is declared.
blabber = [newBlabber copy];
// Refer to the _ivar_, not the property.
unicorn = #"One horn";
return self;
}
#end
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Grimley * g = [[Grimley alloc] initWithBlabber:#"Excelsior"];
// This is how you get around the property.
[g setValue:#"Nimitz" forKey:#"blabber"];
// Again, use the name of the variable, not the property
[g setValue:#"Pearly horn" forKey:#"unicorn"];
NSLog(#"%#", [g blabber]);
NSLog(#"%#", [g narwhal]);
[g release];
[pool drain];
return 0;
}

I am trying to use respondsToSelector but unable to get expected output can anyone find what is wrong in my code?

#import "movie.h"
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// insert code here...
movie *obj = [[movie alloc]init];
[obj findinterestofnum1:(int)200 num2:(int)4 num3:(int)5];
SEL suf = #selector(findinterestofnum1: num2:num3:);
BOOL sul = [obj respondsToSelector:suf];
if(sul)
{
NSLog(#"It is implememted");
}
else
{
NSLog(#" It is not implemented");
}
NSLog(#"Hello, World!");
[pool drain];
return 0;
}
********-----
#interface movie : NSObject {
#private
}
-(void)findinterestofnum1:(int)p num2:(int)n num3:(int)r;
#end
*******-------
#import "movie.h"
#implementation movie
-(void)findinterestofnum1:(int)p num2:(int)n num3:(int)r
{
int a ;
a= (p*n*r/100);
NSLog(#"interest value is =%d",a);
}
- (void)dealloc
{
[super dealloc];
}
#end
i am trying to find whether method is implemented and if it is not it should print it is not implemented
#toddler, respondsToSelector just checks if the corresponding object can respond to that particular method. It doesn't do any checks on whether interface has that definition associated with it since it is a runtime check.
If you had removed the code from the implementation file (.m file) and not the interface, you would have got an error while executing it and you would have found that the BOOL sul is FALSE.

Objective C class initialization errors

I have the following objective C class. It is to store information on a film for a cinema style setting, Title venue ID etc. Whenever I try to create an object of this class:
Film film = [[Film alloc] init];
i get the following errors: variable-sizedobject may not be initialized, statically allocated instance of Objective-C class "Film", statically allocated instance of Objective-C class "Film".
I am pretty new to Objective C and probably am still stuck in a C# mindset, can anyone tell me what I'm doing wrong?
Thanks michael
code:
// Film.m
#import "Film.h"
static NSUInteger currentID = -1;
#implementation Film
#synthesize filmID, title, venueID;
-(id)init {
self = [super init];
if(self != nil) {
if (currentID == -1)
{
currentID = 1;
}
filmID = currentID;
currentID++;
title = [[NSString alloc] init];
venueID = 0;
}
return self;
}
-(void)dealloc {
[title release];
[super dealloc];
}
+(NSUInteger)getCurrentID {
return currentID;
}
+(void)setCurrentID:(NSUInteger)value {
if (currentID != value) {
currentID = value;
}
}
#end
// Film.h
#import <Foundation/Foundation.h>
#interface Film : NSObject {
NSUInteger filmID;
NSString *title;
NSUInteger venueID;
}
+ (NSUInteger)getCurrentID;
+ (void)setCurrentID:(NSUInteger)value;
#property (nonatomic) NSUInteger filmID;
#property (nonatomic, copy) NSString *title;
#property (nonatomic) NSUInteger venueID;
//Initializers
-(id)init;
#end
You need your variable that holds the reference to your object to be of a reference type. You do this by using an asterisk - see below:
Film *film = [[Film alloc] init];
Coming from Java I often think of the above as:
Film* film = [[Film alloc] init];
I tend to associate the 'reference' marker with the type. But hopefully someone more versed in C/C++/ObjC will tell me why this is wrong, and what the 'asterisk' is actually called in this context.