How to save to and read from a NSObject - ios

I have two NSObject's.
#interface Car : NSObject{
#property (strong) NSSet *cars;
}
and
#interface Model : NSObject{
#property (strong) UIImage *picture;
#property (strong) NSString *name;
}
Basically the object Car has a NSSet cars and each object of the NSSet cars has the properties picture and name.
How can I relate this two NSObject's and how can I save a string or image to the Car NSSet using the properties of the Model NSObject. Thanks.

For easy adding or removing, your "cars" property should be declared as a NSMutableSet.
And assuming your single Car object is named "listOfCars", here is one way to do what (I think) you are trying to do:
Model * newModel = [[Model alloc] init];
if(newModel)
{
newModel.picture = [UIImage imageNamed: #"Edsel.jpg"];
newModel.name = #"Ugly Car";
[listOfCars.cars addObject: newModel];
}
And, in your Car .m file, do something like this:
- (id) init
{
self = [super init];
if(self)
{
_cars = [[NSMutableSet alloc] init];
}
return(self);
}
The init method is the only place you should be referring to the underlying variable for your "cars" property. Everywhere else it should be "listOfCars.cars" or "self.cars" if you're referring to the cars set from within the Car object.

Related

Objective-C: work with weak references

I have a few classes:
Book, Publisher, Author and Genre.
So here is the main class Book.h:
#import "Publisher.h"
#import "Author.h"
#import "Genre.h"
#interface Book : NSObject
#property (nonatomic, strong) NSString *bookName;
#property (nonatomic, strong) Author *author;
#property (nonatomic, strong) Publisher *publisher;
#property (nonatomic, weak) Genre *genre;
- (instancetype)initWithBookName:(NSString *)name andAuthorName:(NSString *)authorName
andPublisher:(NSString *)publisherName andGenreName:(__strong NSString *)genreName;
- (NSString *)description;
#end
and his implementation Book.m:
#import "Genre.h"
#import "Book.h"
#import <Foundation/Foundation.h>
#implementation Book
- (instancetype)initWithBookName:(NSString *)name andAuthorName:(NSString *)authorName
andPublisher:(NSString *)publisherName andGenreName:(__strong NSString *)genreName{
self = [super init];
if (self) {
_bookName = [name copy];
_author = [[Author alloc] initWithAuthorName:authorName];
_publisher = [[Publisher alloc] initWithPublisherName:publisherName];
_genre = [[Genre alloc] initWithGenreName:genreName];
}
return self;
}
- (instancetype)init {
return [self initWithBookName:#"unnamed" andAuthorName:#"unnamed" andPublisher:#"unnamed" andGenreName:#"unnamed"];
}
- (NSString *)description {
return [NSString stringWithFormat: #"Book: %#, Author: %#, Genre: %#", self.bookName, self.author, self.genre];
}
#end
I have delegate class - Genre, so to avoid strong reference cycles, a Book's Genre property must be weak.
At this point in the Book.m initializer:
_genre = [[Genre alloc] initWithGenreName:genreName];
it will be nil, because the Genre instance will be deallocated right after assignment.
According to Dan comment, here is my Genre.h:
#import <Foundation/Foundation.h>
#class Book;
#interface Genre : NSObject
#property (nonatomic, strong) NSString *genreName;
#property (nonatomic, strong) NSArray <Book *> *books;
- (instancetype)initWithGenreName:(NSString *)name andBooks:(NSArray <Book *>*)books;
- (instancetype)initWithGenreName:(NSString *)name;
- (NSString *)description;
#end
My question is "What is the best way to store genre object (genreName -> Genre constructor -> genre object) at weak property genre and how do I can store it without using constructor for assignment to weak property?".
SOLUTION: In my case it was collection of Genre and I take my weak property reference to one of objects from my collection.
Genre * genre1 = [[Genre alloc]initWithGenreName:#"Comedy"];
Genre * genre2 = [[Genre alloc]initWithGenreName:#"Drama"];
Genre * genre3 = [[Genre alloc]initWithGenreName:#"Fantastic"];
Genre * genre4 = [[Genre alloc]initWithGenreName:#"National"];
NSArray <Genre*> *genres = #[genre1, genre2, genre3, genre4];
Book *book1 = [[Book alloc] initWithBookName:#"Book #3!" andAuthorName:#"Grinch Burs" andPublisher:#"Ableton" andGenre:[genres objectAtIndex:0]];
The rule to remember is - strong properties increase the reference count, while weak ones do not - and when the reference count gets to 0, a proper is deallocated. So in the case of Genre - at your point in the code, there are no strong references to it so it is deallocated. The solution really is to have the Genres 'owned' by another class. This class would manage the genres, creating them and keeping strong references to them, perhaps in for eg an array of Genres. Your 'strong' genre would be passed in with the initializer, and then the weak reference is the correct approach, preventing a retain cycle, but the dealloc is prevented by the strong property that the Genre property already has - does that make sense?
In a way it makes sense to think of your objects as needing an 'owner' class, where strong references are defined that keep them alive. Then when passed to other classes like your Book class, those have weak references, which prevents the retain cycle as you say. The book class isnt the owner, but someone else is - so it doesnt go away.
One solution would be to make the genre property a strong reference.
If you really need to make Genre a weak reference,
you can solve this by storing all genres in a table and access them statically with something like this:
_genre = [Genre forName:genreName]
The static forName method would then look the correct genre up in a table of all genres. As storing the genre in a table would retain the object, it will not be released immediately on assignment.
#implementation Genre
static NSDictionary* genres;
+ (void) initGenres {
// initialize the dictionary and insert all genres
// or just initalize the dictionary and insert genres on demand
}
+ (Genre*) forName: (NSString*) genreName {
if (!genres) {
[Genre initGenres];
}
//lookup the genre in the dictionary and return it
}
#end
A weak reference does not create a reference count. If there are only weak references to an object, the object will be deallocated. That means if you want an object to stay alive, you either use a strong reference, or you store it somewhere else using a strong reference.
You use weak references to avoid reference cycles, and for objects that are held elsewhere at the moment but might disappear at some point. In your case, using a weak reference is something you won't get working properly.

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

New Object Instances are not running the Customized Initializer

I am working on a project that contains a Singleton instance of a class called Survey. Within that singleton instance is a property called "itemArray," which is an NSMutableArray that contains any number of instances of an Item class.
My Items class contains several NSInteger properties, but for the purposes of the application, I need to initialize all NSIntegers with a value of -1 instead of the default 0.
Now, for my Survey class (the one with the Singleton instance), I use the following method in the implementation to change the default value of a property:
-(id)init {
if (self = [super init]) {
_thingy = -1;
}
return self;
}
This works, but for some reason, the same exact syntax (with different properties) doesn't work for instances of my Item instances. For what it's worth, the following codeblock is the creation of 2 instances of Item, and their insertion into itemArray. I also tried the Item *item1 = [[Item alloc]init; method to no avail.
Item *item1;
[[[Survey sharedInstance]itemArray]insertObject:item1 atIndex:0];
Item *item2;
[[[Survey sharedInstance]itemArray]insertObject:item2 atIndex:1];
}
I would appreciate any assistance.
!!!!!UPDATE!!!!!
I entered the following conditional:
if (![[Survey sharedInstance]itemArray]){
NSLog(#"Test");
}
And the "test" logged onto the console, so it looks like the itemArray isn't being initialized. I'm not sure how to actually initialize it, though. When I try the following:
[[Survey sharedInstance]addressArray] = [[NSMutableArray alloc]init];
I'm getting an error saying "Expression is not assignable."
Survey.h:
#import <Foundation/Foundation.h>
#interface Survey : NSObject
+(instancetype)sharedInstance;
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *emailAddress;
#property (nonatomic, assign) NSInteger trigger1;
#property (nonatomic, assign) NSInteger trigger2;
#property (nonatomic, assign) NSInteger trigger3;
#property (nonatomic, assign) NSInteger activeItem;
#property (nonatomic, strong) NSMutableArray *itemArray;
#end
Survey.m
#import "Survey.h"
#implementation Survey
+ (instancetype)sharedInstance {
static Survey *_instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[Survey alloc] init];
});
return _instance;
}
-(id)init {
if (self = [super init]) {
_storage = -1;
}
return self;
}
#end
Instead of
[[Survey sharedInstance]addressArray] = [[NSMutableArray alloc]init];
you need to use
[Survey sharedInstance].addressArray = [[NSMutableArray alloc]init];
or
[[Survey sharedInstance] setAddressArray:[[NSMutableArray alloc]init]];
You were trying to assign a value to the return value of a getter method, which is not possible, so the compiler was saying "Expression not assignable." You need to use the setter method or dot notation instead.

Access to variable from another class objc

How to access instance variable which is defined in class viewController.
ViewController.h
#interface ViewController : UIViewController
{
Class1* class1;
}
ViewController.m
#implementation ViewController
class1 = [[Class1 alloc]init];
#end
Class1.h
#interface Class1 : NSObject
{
NSMutableArray* variablesArray;
}
#property NSMutableArray* variablesArray;
Class1.m
#implementation Class1
#synthesize variablesArray;
#end
Now I would like to access to instance "class1" variable "variablesArray" from Class2.m. I want to add and get objects from MutableArray "variablesArray". Is it possible?
Yes it is Possible.
Make object of other class and access the variable.
In claas2 import Class1 (#import "Class1")
Class1 *objClass1= [[Class1 alloc] init];
now access like
[objClass1.variableArray addObject:#"object"];
[objClass1.variableArray objectAtIndex:0];
If you want to access same instance of array make a Singleton Class
by adding this class method in your class
+ (Class1 *)sharedInstance
{
static Class1 *shared = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken,
^{
shared = [[self alloc] init];
});
return shared;
}
and access in Class2 like
[[Class1 sharedInstance] variableAray];
Hey you can access variable in another class by Simple making property of the variable like this
#property(nonatomic, strong) NSString *str;
I gave an Answer close to this please check this link
You can access the public property of a class instance by simple using the dot-operator. Notice that there are several ways to encapsulate an instance variable by setting property attributes like (readwrite, readonly).
Class1 aClass = [[Class1 alloc] init];
aClass.varibalesArray addObject:#[ #"someObject" ];
Make sure you initialize the NSMutableArray correctly in the init method of Class1
- (id)init
{
self = [super init];
if (self) {
_variablesArray = [NSMutableArray array];
}
return self;
}

Add object to NSMUtable Array Singleton

I have a shared singleton classNSMutableArray [ICGlobals sharedApplianceCount](first time using this pattern so bear with me if ive done something really silly here)
.h
#import <Foundation/Foundation.h>
#interface ICGlobals : NSObject
{
NSMutableArray* applianceCount;
}
#property (nonatomic, retain) NSString *applianceCount;
+ (ICGlobals *)sharedApplianceCount;
#end
.m
#import "ICGlobals.h"
#implementation ICGlobals
static ICGlobals *sharedApplianceCount = nil;
+ (ICGlobals *)sharedUser {
if(sharedApplianceCount == nil){
sharedApplianceCount = [[super allocWithZone:NULL] init];
}
return sharedApplianceCount;
}
+ (id)allocWithZone:(NSZone *)zone {
return [self sharedApplianceCount];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
#end
In "another view controller" im trying to add the row count of my table view (changeable amount of rows) = self.circuits.count
Having tried this
[[ICGlobals sharedApplianceCount] addObject: self.circuits.count,nil]];
and
[[ICGlobals sharedApplianceCount] = [[NSMutableArray alloc] init];
[[ICGlobals sharedApplianceCount] addObject: self.circuits.count,Nil]];
I get no visible #interface error saying my singleton class declares the selector
same with
NSNumber* numberOfRows = [NSNumber numberWithInteger:self.circuits.count];
[[ICGlobals sharedApplianceCount]addObject:[NSMutableArray arrayWithObjects:numberOfRows, nil]];
and with
[ICGlobals sharedApplianceCount] = self.circuits.count;
I get expression assignable. Singleton class has been imported.
You have an inconsistency in your interface declaration. You declare ivar of type NSMutableArray and then a NSString property. Firstable, you don't need to declare ivar, declaring a property does it for you. So your interface should look like:
#interface ICGlobals : NSObject
#property (nonatomic, retain) NSMutableArray *applianceCount;
+ (ICGlobals *)sharedApplianceCount;
#end
Furthermore, you have a naming glitch. You should not use name applianceCount for an array. In general, naming convention of Cocoa suggests that count should be a number (int or NSUInteger). I would change this property name to applianceCounts.
Then, when you initialize your singletone, you can also initialize the array:
+ (ICGlobals *)sharedUser
{
if(sharedApplianceCount == nil)
{
sharedApplianceCount = [[super allocWithZone:NULL] init];
sharedApplianceCount.applianceCounts = [[NSMutableArray alloc] init];
}
return sharedApplianceCount;
}
Finally, here is how to add data to your singletone's applianceCounts array from view controller.
NSNumber* numberOfRows = [NSNumber numberWithInteger:self.circuits.count];
[[ICGlobals sharedApplianceCount].applianceCounts addObject:numberOfRows];
This should point you to right direction.
I don't fully get what you are trying to achieve like I don't understand why you want to have an array there, so if you need further help please let me know in the comments.
I fully recommend you reading about naming conventions. A good start is this article:
Introduction to Coding Guidelines for Cocoa.
I would recommend some refactoring to your class.
First you make the interface like this:
#interface ICGlobals : NSObject
// add the app count but make it private, because you will provide methods to access it
#property (nonatomic, readonly) NSString *applianceCount;
// return ICGlobals instance
+ (ICGlobals)sharedCounter;
- (NSInteger)count;
- (void)addObject:(id)object;
now in .m file
#implementation ICGlobals
static ICGlobals *sharedApplianceCount = nil;
// this is your method, just changed the name
+ (ICGlobals *)sharedCounter {
if(sharedApplianceCount == nil){
sharedApplianceCount = [[super allocWithZone:NULL] init];
}
return sharedApplianceCount;
}
// instance methods goes here
- (NSInteger)count
{
return _applicationCount.count;
}
- (void)addObject:(id)object
{
[_applicationCount addObject:object];
}
Now call [[ICGlobals sharedCount]addObject:object] from any viewController

Resources