Objective-C Code Structure in Implementation File - ios

#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.

Related

Set property of NSObject

Somehow i can not change the properties of my custom object anymore.
I used Xcode 6 to create my project and moved to XCode 7 now. It told me to "update to recommended settings" and i did it.
Object.h
#interface Object : NSObject <NSCoding>
#property (nonatomic, copy) NSString *ID;
ViewController.m
#import "Object.h"
#interface ViewController ()
#end
Object *myObject;
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
myObject = [[Object alloc] init];
}
- (IBAction)editProperty:(id)sender {
myObject.ID = _textfield.text;
NSLog(#"ID : %#",myObject.ID);
}
This all worked perfectly fine, but now myObject.ID is always (null).....
When i write this code:
myObject.ID = _textfield.text;
NSLog(#"ID : %#",myObject.ID);
inside viewDidLoad it works...
One major issue is this line:
Object *myObject;
What is myObject? It is just floating free. It is not a property. It is not an instance variable. So what is it? That line is legal but it makes little sense.

How to use NSMutableArray from Master Controller in Detail Controller

I am using UISplitViewController and I have a Master Controller and Detail Controller.
The Master Controller I have a NSMutableArray defined like so:
#import "MasterController.h"
#import "DetailController.h"
#interface MasterController ()
#property NSMutableArray *objects;
#end
#implementation MasterController
and I am trying to call it in my Detail Controller like so:
#import "DetailController.h"
#import "MasterController.h"
#interface DetailController ()
{
MasterController *purchaseOrder;
}
#end
#implementation DetailController
- (void)GetRequest
{
NSArray *tableData = [dataSource.areaData GetPurchaseOrderItems:[NSString stringWithFormat:#"%#%#",areaPickerSelectionString,unitPickerSelectionString]];
NSLog(#"%#", tableData);
//TODO: foreach tableData populate object.
[purchaseOrder object];
}
ultimately I am looking to populate the object with each item in tableData. But when I call object, I get this error:
No visible #interface for 'LHPurchaseOrderMaster' declares the selector 'object'
how would I accomplish what I am trying to accomplish ?
So many things amiss here. A few short pointers to hopefully help:
You've put #property NSMutableArray *objects; in your private interface. Try moving this to the header file and making it public. Any reason why you haven't declared this as #property (nonatomic, strong) NSMutableArray *objects; ?
The syntax [someInstance someMethod] means that your purchaseOrder instance of MasterController is trying to call a method called object of which you've not provided us any details about. Perhaps you're trying to call objects instead. But this will only work if you make it public as noted above.
If you're attempting to design a better API than that, you can keep your NSMutableArray of objects private, and provide a public NSArray of maybe *allObjects and inside yourDetailController a getter method like
- (NSArray*)allObjects {
return [self.objects copy];
}
You've not provided any information about LHPurchaseOrderMaster, but hopefully I'm on the right track with helping you solve your problem here.

How to declare array in object and store with encode

I am creating a class Ticket. In that ticket I want a mutable array of NSStrings
i.e. in ticket.h
#interface Ticket : NSObject
#property NSString *ticketName;
#property NSMutableArray *games;
However Objective C doesn't allow me to do this. What am I supposed to do to have an array inside an object?
I then want to store that array using encodeWithCoder in the implementation of the object
like i said you might have a syntax problem, there is no reason why Objective-c won't allow you to add an NSMutableArray into your custom objects, try this:
#interface MyObject : NSObject
#property (nonatomic, strong) NSMutableArray *myMutableArray;
//
// .. other properties
//
#end
and in the implementation
#implementation MyObject
- (void)viewDidLoad
{
[super viewDidLoad];
[self.myMutableArray addObject:#"myString1"];
[self.myMutableArray addObject:#"myString2"];
[self.myMutableArray addObject:#"myString3"];
}

Objective C: allow properties in category via custom root class

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.

Get Access to Object in Obj-c [duplicate]

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.

Resources