How to declare array in object and store with encode - ios

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"];
}

Related

Objective-C Code Structure in Implementation File

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

Hot to create array of objects of class into another class

i have 2 classes i.e one is "MainClass" and another is "StartView" Class .i want to create array of objects of MainClass into StartView Class.
here i created 10 objects of MainClass and added into one Muttable Array .
That Array is also part of MainClass.Its going difficult to access them.
Is there any way to create array of objects directly .I want to know how to access and how to create array of objects in another class. Code Is below ...
//MainClass.h
#import <Foundation/Foundation.h>
#import "StartView.h"
#import "TableViewController.h"
#interface MainClass : NSObject
#property(nonatomic, strong) NSString *que;
#property(nonatomic, strong) NSString *img;
#property(nonatomic, strong) NSArray *option;
#property(nonatomic, strong) NSMutableArray *nms;
-(void)ObjectsAssignment;
#end
//MainClass.m
-(void)ObjectsAssignment
{
nms=[[NSMutableArray alloc]init];
MainClass *mc1=[[MainClass alloc]init];
mc1.que=#"Who invented Microprocessor ?";
mc1.img=#"SuperComputer.jpg";
mc1.option=[[NSArray alloc]initWithObjects:#"Joseph
Jacquard",#"Herman H
Goldstein",#"Marcian E Huff",#"George Boole",nil];
[nms addObject:mc1];
MainClass *mc2=[[MainClass alloc]init];
mc2.que=#".INI extention refers to which kind of file ? ";
mc2.img=#"SuperComputer.jpg";
mc2.option=[[NSArray alloc]initWithObjects:#"Joseph Jacquard",
#"Herman H Goldstein",#"Marcian E Huff",#"George Boole",nil];
[nms addObject:mc2];
}
#end
Create a property in StartView which you can assign the array to. StartView and your other code then share pointers to the same array and both can access it.
In StartView:
#property NSMutableArray *myArrayReference;
Elsewhere
NSMutableArray *theArray=[[NSMutableArray alloc] init];
for (int i=0;i<10;i++){
MainClass *instance=[[MainClass alloc] init];
[theArray addObject:instance]
}
// Pass this array to other object.
StartView *startView=[[StartView alloc] init];
[startView setMyArrayReference:theArray];

How to add a relationship to the parent with Mantle?

I have Parent/child class like this:
#interface Parent : MTLModel <MTLJSONSerializing>
- (void)someMethod;
#property a,b,c...; // from the JSON
#property NSArray *childs; // from the JSON
#end
#interface Child : MTLModel <MTLJSONSerializing>
#property d,e,f,...; // from the JSON
#property Parent *parent; // *not* in the JSON
#end
All the fields a to f are in the JSON, with the same name (hence my JSONKeyPathsByPropertyKey method return nil), and the proper JSONTransformer is correctly setup so that the childs array in parent is containing Child class and not NSDictionary.
Everything work forwardly.
But I want, as a convenience, a property in my Child model that reference back to the parent that own it. So that in the code I can do that:
[childInstance.parent someMethod]
How do I do that with Mantle ??
I want, when the parent is parsing the child's JSON and creating the Child class, to add a ref to itself. (With an init method ??)
Thanks.
I do this by overriding MTLModel -initWithDictionary:error: method. Something like this.
Child interface:
#interface BRPerson : MTLModel <MTLJSONSerializing>
#property (nonatomic, copy, readonly) NSString *name;
#property (strong, nonatomic) BRGroup *group; // parent
#end
In parent implementation:
- (instancetype)initWithDictionary:(NSDictionary *)dictionaryValue error:(NSError **)error {
self = [super initWithDictionary:dictionaryValue error:error];
if (self == nil) return nil;
// iterates through each child and set its parent
for (BRPerson *person in self.people) {
person.group = self;
}
return self;
}
Techinical note:
If you are curious like me, I already tried to tweak MTLJSONAdapter by changing its forwardBlock and reversibleBlock. But I can't, because those are inside MTLReversibleValueTransformer superclass, and that class is declared privately in "MTLValueTransformer.m". So the initWithDictionary approach above should be much easier.

How to make an immutable readonly property in the header file (.h), a mutable readwrite property in implementaion (.m)

I have an object that holds a dictionary JSONData. From the header file, and to the other classes that'll access it, I want this property to only be read-only and immutable.
#interface MyObject : NSObject
#property (readonly, strong, nonatomic) NSDictionary *JSONData;
#end
However, I need it to be readwrite and mutable from the implementation file, like this, but this doesn't work:
#interface MyObject ()
#property (readwrite, strong, nonatomic) NSMutableDictionary *JSONData;
#end
#implementation MyObject
// Do read/write stuff here.
#end
Is there anything I can do to enforce the kind of abstraction I'm going for? I looked at the other questions and while I already know how to make a property readonly from .h and readwrite from .m, I can't find anything about the difference in mutability.
You need a separate private mutable variable in your implementation. You can override the getter to return an immutable object.
#interface MyObject () {
NSMutableDictionary *_mutableJSONData;
}
#end
#implementation MyObject
// ...
-(NSDictionary *)JSONData {
return [NSDictionary dictionaryWithDictionary:_mutableJSONData];
}
// ...
#end
No need to implement the setter, as it is readonly.

How to get View object to respond to changes to its data source

Say I have a CatModel object:
#interface CatModel : NSObject
#property (nonatomic, copy) NSString *name;
#property (nonatomic, strong) UIImage *catImage;
- (void)addWhisker:(Whisker*)whisker;
And I have a CatView:
#interface CatView : UIView
#property (nonatomic, strong) CatModel *dataSource;
#end
I want the CatView to automatically add a whisker image when it detects that a whisker was added to its dataSource. I don't want to add a Whisker to the CatModel instance and also add an addWhisker method to the CatView. What's the best way to do this?
Sounds like you may use key-value observing, but unfortunately, NSArray or any other collections are not KVO-compatible.
Instead, you may wish to create a delegate functionality:
#protocol CatModelObserving
#optional
- (void)catModel:(CatModel *)model didAddWhisker:(Whisker *)whisker;
#end
...
#interface CatModel
#property (weak, nonatomic) id <CatModelObserving> observer;
#end
Then you would ensure that the CatView conforms to that protocol and implements that method:
- (void)catModel:(CatModel *)model didAddWhisker:(Whisker *)whisker {
// handle it properly
}
In your CatModel.m, inside the -addWhisker: method you should notify the observer that a whisker has been added:
if (self.observer && [self.observer respondsToSelector:#selector(catModel:didAddWhisker:)]) {
[self.observer catModel:self didAddWhisker:whisker];
}
If you wish to have multiple "observers", you may consider using GCD and block-based "notifications", like so:
[catModel addDidAddWhiskerBlock:^(Whisker *whisker) {
// handle it properly
}];
But I will not discuss that method in this answer. As a hint I can suggest using NSMutableArray storing all those blocks, then iteratiating through those blocks in the -addWhisker: method and calling each block.

Resources