I am using the iPhone SDK and have an issue doing something simple. I am trying to add an NSNumber object to an NSMutableArray instance variable. I tried adding NSNumber card to NSMutableArray viewedCardsArray, however without breaking, it does not get added to the array. Here is the code.
/////////////////////////////////////////////////////
// Inside the header file Class.h
#interface MyViewController : UIViewController {
NSMutableArray *viewedCardsArray;
//snip ...
}
#property (nonatomic, retain) NSMutableArray *viewedCardsArray;
#end
/////////////////////////////////////////////////////
// Inside the methods file Class.m
#import "StudyViewController.h"
#implementation StudyViewController
#synthesize viewedCardsArray
//snip ...
- (IBAction)doShowCard {
//snip ...
NSNumber *cardIdObject = [[NSNumber alloc] initWithInt:(int)[self.currentCard cardId]];
[viewedCardsArray addObject: cardIdObject];
[cardIdObject release];
}
So this code executes, and does not seem to leak (according to the Leaks performance tool). However when stepping through the code, at no point does CardIdObject appear in viewedCardsArray.
Looking through SO, I know these basic questions are pretty common to ObjC newbies (like me) so apologies in advance!
Have you initialized your viewedCardsArray? If not you need to somewhere - this is usually done in the init method for your class:
- (id)init
{
self = [super init];
if(self) {
viewedCardsArray = [[NSMutableArray alloc] init];
}
return self;
}
Then it is released in the dealloc method:
- (void)dealloc
{
[viewedCardsArray release];
[super dealloc];
}
Perspx has outlined one way of initializing the array. However, you can also use the class methods provided by NSArray:
self. viewedCardsArray = [NSMutableArray array];
This can go in init or elsewhere.
Note: The object will be autoreleased.
Related
The object created deallocated after viewDidLoad: method in Cocoa
Please see the code below:
#import "ShowTableViewController.h"
#interface ShowTableViewController ()
#property NSArray *data;
#end
#implementation ShowTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.data = #[#"One", #"Two", #"Three"];
NSLog(#"%ld",self.data.count);
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
NSLog(#"%ld",self.data.count);
return self.data.count;
}
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
return self.data[row];
}
#end
The output is
3
0
I checked the execution order using breakpoints viewDidLoad is called first!
I resolved it by using awakeFromNib method. but i want to know why this is happening
Any help would be appreciated.
You need to reload your tableView in viewDidLoad after assigning your array like this
- (void)viewDidLoad {
[super viewDidLoad];
self.data = #[#"One", #"Two", #"Three"];
[self.tableView reloadData];
NSLog(#"%ld",self.data.count);
}
This have solved my problem, hope it will solve your too.
I had to objects in total. One in the interface builder and another one created by me in code. the object was not getting deallocated. the second object was assigned as the datasource, so it was returning zero. Its a honest mistake on my part. Sorry for wasting your time. Thanks you all for the answers :)
Try to declare your data property as strong
#property NSArray *data;
becomes
#property (strong) NSArray *data;
#interface OuterSpaceController ()
//Cannot alloc and init my array here for some reason
NSMutableArray *spaceObjectsAsPropertyLists = [[NSMutableArray alloc] init];
#end
//But could do it here... Can someone explain why this is the case?
NSMutableArray *spaceObjectsAsPropertyLists = [[NSMutableArray alloc] init];
#implementation OuterSpaceController
#end
Hi I had a question regarding this code structure in objective-C. My first question is why is this portion even present in the implementation file?:
#interface OuterSpaceController ()
#end
I tried creating my NSMutableArray there^^^, so I can access it in all my methods in the implementation file, but I was not able to for some reason. Also regarding my NSMutableArray if I create it in between the #end and #implementation OuterSpaceController lines of code (like shown in my first block of code), will my NSMutableArray be allocated and initialized every time my view controller is loaded in memory? And if not when does the allocation and initialization of this NSMutableArray *spaceObjectsAsPropertyLists Mutable Array happen?
Thank you so much for the help in advance!
This is called a class extension:
#interface OuterSpaceController ()
#end
Extensions allow you to add declarations to your class. See Apple's docs for details. This is mostly used for declaring properties or methods in a different scope of the original declaration. Something like this:
// Foo.h
#interface Foo
#property (strong) NSArray * everyoneCanSeeThis;
#end
// Foo.m
#interface Foo ()
#property (strong) NSArray * thisIsOnlyVisibleInThisFile;
#end
There are other uses to extensions. I recommend you read Apple's docs.
Your other question is not related to this. In order to initialise the spaceObjectsAsPropertyLists property you have two options. One, when initialising the class:
#interface OuterSpaceController ()
// Does not initialise, just declares. This is an interface, not an implementation
#property (strong) NSMutableArray *spaceObjectsAsPropertyLists;
#end
#implementation OuterSpaceController
- (instancetype)init
{
self = [super init];
if (self) {
_spaceObjectsAsPropertyLists = [NSMutableArray array];
}
return self;
}
#end
In this case the array is instantiated as soon as the class is initialised, but there's a second option. There's another way of initialising classes called Lazy Initialisation. Here's how it goes:
#interface OuterSpaceController ()
// Does not initialise, just declares. This is an interface, not an implementation
#property (strong) NSMutableArray *spaceObjectsAsPropertyLists;
#end
#implementation OuterSpaceController
- (instancetype)init
{
// Do not instantiate!
return [super init];
}
- (NSMutableArray *)spaceObjectsAsPropertyLists
{
if (_spaceObjectsAsPropertyLists == nil) {
_spaceObjectsAsPropertyLists = [NSMutableArray array];
}
return _spaceObjectsAsPropertyLists;
}
#end
The general idea is to override the property's getter. The upside of this method is that the property will be initialised only as soon as it is needed, and not sooner. This method is usually more memory friendly.
You need to know that your interfaces can only contain declarations. It's the implementation section who's responsible for pretty much everything else.
In some reason, I have to use a design pattern that an object remove itself from its container, consider the following code(ARC is enabled, LCDObject is an object class, LCDContainer is a container class), in the whole program, object 's reference count is always 1 until it is removed from the container(reference count become 0), as comment 2 mention, when [_container removeObject:self] return, the object's reference count is 0, it is dealloc, right?, but the process is still in the object's method -- "removeFromContainer", what would happen? Does the following code would be execute successfully? Does "removeFromContainer" can return successfully?
I run this code in Xcode, the "NSLog" in "removeFromContainer" can be invoked successfully, but I can't figure out why...
//-------------------------------------------------------------
#import <Foundation/Foundation.h>
#interface LCDContainer : NSObject
#property (strong, nonatomic) NSMutableArray *objects;
- (void)removeObject:(id)object;
- (id)addObject:(id)object;
#end
#implementation LCDContainer
- (id)init {
self = [super init];
if (self) {
_objects = [[NSMutableArray alloc] init];
}
return self;
}
- (id)addObject:(id)object {
[_objects addObject:object];
return object;
}
- (void)removeObject:(id)object {
[_objects removeObject:object];
}
#end
//-------------------------------------------------------------
#interface LCDObject : NSObject
#property (weak, nonatomic) LCDContainer *container;
- (id)initWithContainer:(LCDContainer*) container;
- (void)removeFromContainer;
#end
#implementation LCDObject
- (id)initWithContainer:(LCDContainer *)container {
self = [super init];
if (self) {
_container = container;
// (1) add the object to the Container, now its reference count is 1
//
[container addObject:self];
NSLog(#"add to container.");
}
return self;
}
- (void)removeFromContainer {
// (2) remove the object from the Container, now its reference count is 0,
// the object is delete, does the following "NSLog" would be invoked successfully?
//
[_container removeObject:self];
NSLog(#"remove from container.");
}
#end
//-------------------------------------------------------------
int main(int argc, const char * argv[]) {
#autoreleasepool {
LCDContainer *container = [[LCDContainer alloc] init];
[[LCDObject alloc] initWithContainer:container];
[[[container objects] objectAtIndex:0] removeFromContainer];
}
return 0;
}
I've not tried your code but I suspect it will work. sapi's suggestion (adding a breakpoint or NSLog on dealloc) is a good one to confirm, though.
Thee are two ways that ARC could be doing this. You can check the assembler if you're really interested.
The simplest is to assume that it's using autorelease, that is, when an object is removed from your container it gets added to the autorelease pool and is released (and dealloced) at the end of the current run loop.
The other way is to consider where ARC adds its retains and releases. This question notes that your remove method really looks like this:
- (void)removeObject:(id)object {
[object retain];
[_objects removeObject:object];
[object release];
}
The call to removeObject: may well have the same logic. This means that object does not get released as soon as the removeObject: call is completed; the object lifecycle is almost certainly (slightly) longer than that.
I have a custom class/object that handles gestures and conducts animations for a given view using a CADisplayLink. In its simplest form my class looks something like follows:
#interface SomeClass : NSObject
#property (strong) UIView *someView;
#end
When I add the following code to my view controller....
- (void)viewDidLoad
{
[super viewDidLoad];
SomeClass *someClass = [[SomeClass alloc] init];
someClass.someView = someView;
}
... I was anticipating my someClass object would be retained for the life of the view controller, since I am using a strong reference to someView.
However someClass is immediately deallocated.
I am already aware that I can overcome the deallocation simply by adding someClass as a property (or indeed iVar) of the view controller however I would ideally like to avoid this extra work...
so is there anyway I can have my class retained until either the view or view controller its associated with are deallocated?
EDIT
UIGestureRecognizer objects are an exmaple of a class that doesn't get deallocated when I associate them with a view...
- (void)viewDidLoad
{
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] init];
[someView addGestureRecognizer:gestureRecognizer];
}
// tapGestureRecognizer still lives
Presumably this is because the UIView takes owner ship of the UIGestureRecognizer object. Is there anyway to achieve this with my class and a UIView category? I.e....
- (void)viewDidLoad
{
[super viewDidLoad];
SomeClass *someClass = [[SomeClass alloc] init];
[someView addSomeClass:someClass];
}
If you want to associate the object with a UIView in the same way a UIGestureRecognizer does then this is technically possible using associatedObjects as follows (but I'm not sure I'd advocate this approach since associatedObjects are often frowned upon)...
SomeClass.h
#class SomeClass;
#interface UIView (SomeClass)
- (void)addSomeClass:(SomeClass *)someClass;
- (void)removeSomeClass:(SomeClass *)someClass;
#end
#interface SomeClass : NSObject
#property (strong) UIView *someView;
#end
SomeClass.m
#import "SomeClass.h"
#import <objc/runtime.h>
#implementation UIView (AssociatedObject)
- (void)addSomeClass:(SomeClass *)someClass
{
NSMutableArray *someClasses = [self someClasses];
if (someClasses == nil) {
someClasses = [[NSMutableArray alloc] init];
[self setSomeClasses:someClasses];
}
[someClasses addObject:someClass];
}
- (void)removeSomeClass:(SomeClass *)someClass
{
NSMutableArray *someClasses = [self someClasses];
if (someClasses != nil) {
[someClasses removeObject:someClass];
if (someClasses.count == 0) {
[self setSomeClasses:nil];
}
}
}
#pragma mark - Private Methods
- (NSMutableArray *)someClasses
{
return (NSMutableArray *)objc_getAssociatedObject(self, #selector(someClasses));
}
- (void)setSomeClasses:(NSMutableArray *)someClasses
{
objc_setAssociatedObject(self, #selector(someClasses), someClasses, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#end
#implementation SomeClass
#end
Implementation
- (void)viewDidLoad
{
[super viewDidLoad];
SomeClass *someClass = [[SomeClass alloc] init];
someClass.someView = someView;
[someView addSomeClass:someClass];
}
Some further reading on associatedObjects from NSHipster...
http://nshipster.com/associated-objects/
But you can declare SomeClass instance instead of property like this:
#implementation ViewController
{
SomeClass* _someClass;
}
...
- (void)viewDidLoad
{
[super viewDidLoad];
_someClass = [[SomeClass alloc] init];
_someClass.someView = someView;
}
Your SomeClass instance is holding a strong reference to the someView, but nothing is holding a reference to the SomeClass instance except the local variable inside your viewDidLoad message, so as soon as the method exits, that instance can be deallocated. As that was the object holding the only reference to your UIView the view can also be deallocated.
Your only options are to store the reference to the SomeClass object in an instance variable (or iVar) as stosha suggested or in a property. Properties are the preferred method and with automatic synthesis they don't take much more effort than a local variable declaration.
You can declare the property inside the .m file so that it isn't visible to other classes that reference your ViewController class -
In your ViewController.m file -
#interface ViewController ()
#property (strong, nonatomic) SomeClass *someClass;
#end
#implementation ViewController
...
(void)viewDidLoad
{
[super viewDidLoad];
self.someClass = [[SomeClass alloc] init];
self.someClass.someView = someView;
}
There are many questions concerning the category-properties problem.
I know some possibilities to address this:
use a singleton registry
objc_setAssociatedObject and objc_getAssociatedObject
From my point of view both is not clean since the memory allocated is never cleared when the object that created such properties is deallocated.
Categories are a good way to keep code clean and dynamically add functionality to already existing classes. They help to group functionality and to distributed implementation work among more developers.
The bad about categories is the missing storage.
I came across this problem several times now and I'm wondering whether the following would address this problem in an clean way that also takes care about the memory and if there are any problems that I can't see right now.
There is one restriction, that I can ignore since I'm working as a framework developer: I'm able to create my own root class that all my other classes can inherit from.
First of all declare the new root object:
#interface RootObject : NSObject
- (void)setRuntimeProperty:(id)runtimeProperty forKey:(id<NSCopying>)key;
- (id)runtimePropertyForKey:(id)key;
#end
With the corresponding implementation:
#import "RootObject.h"
#interface RootObject ()
#property (readwrite) NSMutableDictionary *runtimeProperties;
#end
#implementation RootObject
#synthesize runtimeProperties = _runtimeProperties;
- (id)init {
self = [super init];
if (self)
{
_runtimeProperties = [[NSMutableDictionary alloc] initWithCapacity:1];
}
return self;
}
- (void)dealloc {
[_runtimeProperties release];
_runtimeProperties = nil;
[super dealloc];
}
- (id)runtimePropertyForKey:(id)key {
return [self.runtimeProperties objectForKey:key];
}
- (void)setRuntimeProperty:(id)runtimeProperty forKey:(id<NSCopying>)key {
if (key)
{
if (runtimeProperty)
{
[self.runtimeProperties setObject:runtimeProperty forKey:key];
}
else
{
[self.runtimeProperties removeObjectForKey:key];
}
}
}
#end
By using this RootObject instead of NSObject it should be very easy to add a "property" to a category on a class. Consider having some class MyClass
#interface MyClass : RootObject
// some interface here
#end
When implementing a special behavior on top of this class you are now able to add a property like this:
#interface MyClass (specialBehavior)
#property (nonatomic, retain) NSString *name;
#property (nonatomic, copy) NSDate *birthday;
#end
With corresponding implementation:
#implementation MyClass (specialBehavior)
#dynamic name;
- (NSString *)name {
return [self runtimePropertyForKey:#"name"];
}
- (void)setName:(NSString *)name {
[self setRuntimeProperty:name forKey:#"name"];
}
#dynamic birthday;
- (NSDate *)birthday {
return [self runtimePropertyForKey:#"birthday"];
}
- (void)setBirthday:(NSDate *)birthday {
[self setRuntimeProperty:[birthday copy] forKey:#"birthday"];
}
#end
Such an implementation could KVO compatible as well by just adding the necessary calls in the setter method.
Very straight forward, but I'm wondering whether I missed something important? (E.g. very very bad runtime performance having many such declared properties or using many of these objects)
This is effectively the same as objc_setAssociatedObject and objc_getAssociatedObject, which do release memory when the object is deallocated (depending on the association type). I would guess they also have much lower overhead than your suggested code.