I'm learning about retain and release methods for counting references in Objective-C, but Instruments says that is still living 1 reference of MyClass, the code:
#import <Foundation/Foundation.h>
#import "MyClass"
int main(int argc, const char * argv[])
{
#autoreleasepool {
MyClass *obj;
for (int i=0; i < 200000; i++){
obj = [[MyClass alloc] init];
[obj setSomeValue:100];
NSLog(#"itineration %i", i);
[obj release];
}
}//#autoreleapool
}//main
MyClass.h
#interface MyClass : NSObject
#property int someValue;
#end
Why Instruments shows "16LiveBytes" "1#Living" "199999#Transient" "200000#Overall" in MyClass? Should be 0 right?
Related
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
Does anyone know why this code is running into compilation errors? I'm compiling it on Catalina using clang. I posted a similar issue here but that was when I was trying to compile using clang on Linux. I thought getA and setA are auto-generated by synthesize. Thanks!
#import <Foundation/Foundation.h>
#interface A: NSObject
#property int a;
#end
#implementation A
{
int a;
}
#synthesize a;
#end
int main (int argc, char * argv[])
{
#autoreleasepool {
A *a = [[A alloc] init];
[a setA:99];
int v = [a getA];
NSLog (#" %d\n", v);
}
return 0;
}
Compilation:
$ clang -framework Foundation otest0.m -o hello
otest0.m:23:16: warning: instance method '-getA' not found (return type defaults
to 'id') [-Wobjc-method-access]
int v = [a getA];
^~~~
otest0.m:3:12: note: receiver is instance of class declared here
#interface A: NSObject
^
otest0.m:23:9: warning: incompatible pointer to integer conversion initializing
'int' with an expression of type 'id' [-Wint-conversion]
int v = [a getA];
^ ~~~~~~~~
2 warnings generated.
The getter/setter pair is synthesized as
-(int)a;
-(void)setA:(int)val;
So you need:
int main (int argc, char * argv[])
{
#autoreleasepool {
A *a = [[A alloc] init];
[a setA:99];
int v = [a a];
NSLog (#" %d\n", v);
}
return 0;
}
Declaring a property with name a produces a getter with name a, not getA.
This is what the first warning is about: "instance method '-getA' not found"
This works on my system (macOS):
#import <Foundation/Foundation.h>
#interface A: NSObject
#property int a;
#end
#implementation A {
int a;
}
#synthesize a;
-(int) getMyValue {
return a;
}
#end
int main () {
#autoreleasepool {
A *a = [[A alloc] init];
[a setA:99];
NSLog (#"value = %d", [a getMyValue]);
}
return 0;
}
If file is saved as synth.m the terminal command is: clang synth.m -framework Foundation -o synth && ./synth
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;
}
Here is an example of how the properties of a javascript object can be enumerated through. I noticed that the loop construct used was a for...in loop. Objective-C also has a for...in loop, so is the same behavior possible in Objective-C?
#interface Bar : NSObject
#property (nonatomic) NSString * stringA;
#property (nonatomic) NSString * stringB;
#property (nonatomic) NSString * stringC;
#end
int main(int argc, const char *argv[]) {
Bar obj = [[Bar alloc] init];
obj.stringA = #"1";
obj.stringB = #"2";
obj.stringC = #"3";
for (NSString *property in obj) {
NSLog(#"%#", property);
}
}
Is this possible with Objective-C? If not, is there an alternative that would mimmic this behavior of iterating through an objects properties?
Short answer: yes it is possible.
Here's some sample code of what you're trying to achieve.
Header
#interface Bar : NSObject
#property (nonatomic, retain) NSString *stringA;
#property (nonatomic, retain) NSString *stringB;
#property (nonatomic, retain) NSString *stringC;
#end
Main
#implementation Bar
// don't forget to synthesize
#synthesize stringA, stringB, stringC;
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
unsigned int numberOfProperties = 0;
objc_property_t *propertyArray = class_copyPropertyList([Bar class], &numberOfProperties);
for (NSUInteger i = 0; i < numberOfProperties; i++)
{
objc_property_t property = propertyArray[i];
NSString *letter = [[NSString alloc] initWithUTF8String:property_getName(property)];
NSString *attributesString = [[NSString alloc] initWithUTF8String:property_getAttributes(property)];
NSLog(#"Property %# attributes: %#", letter, attributesString);
}
free(propertyArray);
}
}
Let me know if you have any questions.
Fast enumeration
Bar *obj = [[Bar alloc] init];
// ...
for (id elem in obj) {
...
}
requires that the class Bar conforms to the NSFastEnumeration Protocol, i.e. it must implement the
countByEnumeratingWithState:objects:count:
method. (This is the case for all Objective-C collection classes such asNSArray, NSDictionary, NSSet.)
So the direct answer to your question is no, you cannot use the fast enumeration syntax for (... in ...) to enumerate all properties of an arbitrary class.
However, it is possible to implement the fast enumeration protocol for a custom class.
Examples how this is done can be found here
https://developer.apple.com/library/mac/samplecode/FastEnumerationSample/Introduction/Intro.html
http://www.cocoawithlove.com/2008/05/implementing-countbyenumeratingwithstat.html
I would like to know how weak property work in Objective-C.
In this example the value of the weak property "myString" in "myClass" is kept only when I print it with NSLog. Why is that?
#import <Foundation/Foundation.h>
#include <stdio.h>
#interface myClass : NSObject
#property (nonatomic, weak)NSString *myString;
- (void)readString;
#end
#implementation myClass
#synthesize myString;
- (void)readString
{
const int MAXBUFFER = 80;
char buffer[MAXBUFFER+1];
NSLog(#"Input string:");
fgets(buffer, MAXBUFFER, stdin);
NSString *tempString = [[NSString alloc] initWithUTF8String:buffer];
myString = tempString;
NSLog(#"myString: %#", myString); // Why does this line make all the difference?
}
#end
int main(int argc, const char * argv[])
{
#autoreleasepool
{
myClass *myInstance = [[myClass alloc] init];
[myInstance readString];
NSLog(#"myInstance.myString: %#", myInstance.myString);
}
return 0;
}
If the NSLog-line in the readString-method is commented out myInstance.myString becomes "(null)". Why??
From Apple:
weak Specifies that there is a weak (non-owning) relationship to the
destination object. If the destination object is deallocated, the
property value is automatically set to nil.
So Basically when arc insert code into [readString], he does:
NSString *tempString = [[NSString alloc] initWithUTF8String:buffer];
myString = tempString;
// + arc [tempString release]
So your tempString no longer exist outside the method, because nothing retain it.
But when you add NSlog inside [readString] with myString, NSLog will keep reference to the pointer (i don't know exactly how), but he actually does since he logs them.