Store an NSArray globally to save data bandwidth from downloading content - ios

I am making an application which as a part of it needs to download information from 2 RSS feeds.
However these feeds will have that information used across the entire app and may or may not be reloaded as the user requires to see their selected UIViewController.
So my question is:
Is it advisable to setup these arrays on application load in the UIAppDelegate or is that a big no-no in regards to performance?
I have the code working, I am just wanting to know what the best place would be to execute it to minimize data usage and also at the same time be best accessible throughout the app?
Any help would be great, because there is a lot of code to shift around if I need to keep re-doing this.
Thanks for the advice.
PS I know there is a lot of reading I can do and am doing, using SO is part of this research to get developers opinions. I hope that it does not break any rules or upset people :-)

Create a File as an NSObject, do header like this;
#interface myData : NSObject
{
NSMutableArray *myDataArray;
}
#property (nonatomic, retain) NSMutableArray *myDataArray;
+ (myData *)sharedData;
#end
Then in the .m add this
#import “myData.h”
static myData *sharedData;
#implementation myData
#synthesize myDataArray;
+ (myData *)sharedData
{
if(!sharedData)
{
sharedData = [[myData alloc] init];
}
return sharedData;
}
- (id)init
{
self = [super init];
if(self)
{
myDataArray = [[NSMutableArray alloc] init];
}
return self;
}
Then in each of your VCs, simply #import "myData.h" and when you need it do this;
myData *localShared = [myData sharedData];
localShared.myDataArray = // This is your array and will look the same throughout
NSString *myStringObj = localShared.myDataArray[4]; // So you can do this kind of stuff
This from memory, I have not tested but I think this is very close. Hope it helps.

Related

How to create referencing variables?

I'm making an app for practice. This app shares with a simple model through AppDelegate. To manipulate the model, I got an NSDictionary object from the model and allocate it to a viewController property. but It seems too verbose.
// viewController.h
#property (nonatomic, strong) NSMutableDictionary *bookDetail;
#property (nonatomic, strong) bookModel *modelBook;
// viewController.m
- (void)setLabel {
self.label_name.text = self.bookDetail[#"name"];
self.label_author.text = self.bookDetail[#"author"];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
id appDelegate = [[UIApplication sharedApplication] delegate];
self.modelBook = [appDelegate modelBook];
self.bookDetail = self.modelBook.bookList[self.modelBook.selectedId];
[self setLabel];
self.editMod = NO;
}
- (IBAction)editSave:(id)sender {
if (self.editMod == NO) {
....
[self.nameField setText:self.bookDetail[#"name"]];
[self.authorField setText:self.bookDetail[#"author"]];
....
} else {
self.bookDetail = [#{#"name" : self.nameField.text,
#"author" : self.authorField.text} mutableCopy];
[self setLabel];
....
}
}
#end
*bookDetail work like a copy of self.modelBook.bookList[self.modelBook.selectedId] not a reference. Using self.modelBook.bookList[self.modelBook.selectedId] works well, but I don't want to. How Can I simplify this code?
*bookDetail work like a copy of self.modelBook.bookList[self.modelBook.selectedId] not a reference. Using self.modelBook.bookList[self.modelBook.selectedId] works well, but I don't want to.
Your question is not clear to me so this might be wrong, but hopefully it helps.
bookDetail is not a "copy" in the usual sense, rather it is a reference to the same dictionary that self.modelBook.bookList[self.modelBook.selectedId] references at the time the assignment to bookDetail is made.
Given that you say that using the latter "works well" is sounds as though self.modelBook.selectedId is changing and you expected bookDetail to automatically track that change and now refer to a different dictionary. That is not how assignment works.
How Can I simplify this code?
You could add a property to your modelBook class[1], say currentBook, which returns back bookList[selectedID] so each time it is called you get the current book. In your code above you then use self.modelBook.currentBook instead of self.bookDetail and can remove the property bookDetail as unused (and incorrect).
HTH
[1] Note: this should be called ModelBook to follow naming conventions. Have you noticed the syntax coloring is incorrect? That is because you haven't followed the convention.
Create the shared instance of BookModel then you can access it anywhere:
Write this in bookModel:
+ (instancetype)sharedInstance
{
static bookModel *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[bookModel alloc] init];
// Do any other initialisation stuff here
});
return sharedInstance;
}
Then you can access this like bookModel.sharedInstance.bookList

Setters, Getters and Exposing real core data types, how do I do that?

I have a core data entity that has a structure like this:
number (integer 16),
reference (binary)
image (binary)
I have created a class for that entity.
The header of that class has these declarations for the entity property.
#property (nonatomic, retain) NSNumber * number;
#property (nonatomic, retain) NSData * reference;
#property (nonatomic, retain) NSData * image;
but in fact, these 3 properties are
number = NSInteger
reference = NSArray
image = UIImage
because I cannot store arrays and images on core data directly, I have to convert it to NSData to save but I don't care for the property being declared as NSData, because the conversion to and from NSData is something internal to the entity and should not be exposed to code outside the class.
I want these header properties to be declared like
#property (nonatomic, assign) NSInteger number;
#property (nonatomic, retain) NSArray * reference;
#property (nonatomic, retain) UIImage * image;
and I want to, for example, when I assign an array to reference that is converted to NSData internally.
I know I have to create setters and getters to do that but my problem is that the entity is already using these names. Obviously I can rename all core data entities to have a prefix like xnumber, xreference, ximage, etc., so I will have no collisions between the names/types I want to expose and those I want to hide internally.
Is there any other alternative to that? My fear is ending with a sea of references that are similarly.
What you did in your application is probably most common fail using core data. By no means you should be encouraged to use the core data classes directly as you did, do always use subclassing, categories or (best of all) use wrappers.
Since in most cases when you edit an entity in your model you wish to delete the auto generated file(s) and create new ones those files should be unmodified. This is the main reason I discourage you to use any quick fixes such as modifying the names in your model and then creating the custom setters.
Why I suggest the wrappers most is because you can build your own interface with it. You can create exactly as many methods, accessories as you need on it, you can use data protection such as having read-only parameters... So when you modify the data model there should be no difference in the application at all, when you will possibly add some extra tables for some optimisations or some internal functionality you will have no issues hiding those accessories. Other then that having an extra layer will make it very easy for you to create some caching, easy debugging since you can put a breakpoint or log to more or less any and every accessory, you can internally maintain multithreading operations...
I can understand at this point migrating your code to some other system might take a bit long but that is something you should consider. If the application is anything but almost done I suggest you do migrate it: If you create a wrapper with same properties as are already used in the application it is possible to simply change the class names where it was already used, this shouldn't take too long. If you choose to continue working as it is you will most likely encounter some much harder issues and if nothing else remember this when you will start a new application.
Edit: Wrapper explanation and example
By wrapper I mean a class instance that holds another instance and builds an interface around it. Let me show you a nice example first:
Interface:
#interface EntityWrapper : NSObject
#property NSInteger number;
#property UIImage *image;
+ (NSArray *)fetchAll;
+ (void)invalidateCache;
#end
Implementation:
#class EntityName;
static NSArray *__entityCache = nil;
#interface EntityWrapper() {
EntityName *_boundEntity;
}
#end
#implementation EntityWrapper
- (instancetype)initWithEntity:(EntityName *)entity {
if((self = [super init])) {
_boundEntity = entity;
}
return self;
}
+ (NSArray *)fetchAll {
if(__entityCache == nil) {
NSMutableArray *toReturn = [[NSMutableArray alloc] init];
NSArray *entityArray = nil; //fetch from data base
for(EntityName *entity in entityArray)
[toReturn addObject:[[EntityWrapper alloc] initWithEntity:entity]];
__entityCache = [toReturn copy];
}
return __entityCache;
}
+ (void)invalidateCache {
__entityCache = nil;
}
- (void)setNumber:(NSInteger)number {
_boundEntity.number = #(number);
}
- (NSInteger)number {
return [_boundEntity.number integerValue];
}
- (void)setImage:(UIImage *)image {
_boundEntity.image = UIImagePNGRepresentation(image);
}
- (UIImage *)image {
return [[UIImage alloc] initWithData:_boundEntity.image];
}
#end
As you can see here I am building an interface around the entity using custom setters and getters. I even create a method to fetch all objects from the data base, next step might be to fetch them with some predicate or in this case rather some custom options. I also added a most simple cache just to see the concept.
The number is now a NSInteger instead of a NSNumber which can be quite a convenience but be careful doing this as you might need to know if number is nil. For this case you could also create another property such as BOOL numberIsSet.
Pretty much the same goes for the image. You need no transformers at all, just a getter and a setter (which is pretty much the same with transformers but this approach is much more dynamic).
So creating the wrapper kind of gives you the ultimate power. The idea is to create as small interface as possible and as simple as possible. That means there are just as many methods in the header file as needed, rest is hidden. The logic behind these methods can be extremely complicated but will still be maintainable since it is a closed system (does not depend on nothing but the entity), to give you an example:
Interface:
#property (readonly) NSDecimalNumber *heavyValue;
Implementation:
- (NSDecimalNumber *)heavyValue {
NSDecimalNumber *valueA = _boundEntity.valueA;
NSDecimalNumber *valueB = _boundEntity.valueB;
NSDecimalNumber *valueC = _boundEntity.valueC;
return [[valueA decimalNumberByAdding:valueB] decimalNumberByDividingBy:valueC];
}
Now this is quite a standard procedure and will work great but this method can be quite heavy on the CPU. If this method is called a lot you might get to a point where you want to optimise by storing the result into the entity itself. So all you do is add another value into the model heavyValue and the code:
- (NSDecimalNumber *)heavyValue {
NSDecimalNumber *toReturn = _boundEntity.heavyValue;
if(toReturn == nil) {
NSDecimalNumber *valueA = _boundEntity.valueA;
NSDecimalNumber *valueB = _boundEntity.valueB;
NSDecimalNumber *valueC = _boundEntity.valueC;
toReturn = [[valueA decimalNumberByAdding:valueB] decimalNumberByDividingBy:valueC];
_boundEntity.heavyValue = toReturn;
}
return toReturn;
}
- (void)setValueA:(NSDecimalNumber *)valueA {
_boundEntity.valueA = valueA;
_boundEntity.heavyValue = nil; //this invalidates the value
}
So that is quite an extreme change in logic behind a simple getter but the rest of your code is unharmed, it still all works as it should.

Is it okay to lazy initialization/load all objects?

I find myself lazy initialization all my functions now. It just feels more natural and it allows me to to stop writing setup functions. Is this bad by design? What are the pitfalls?
#property (nonatomic, strong) NSMutableArray *array1;
-(NSMutableArray *)array1{
if (!_array1){
_array1 = [[NSMutableArray alloc] init];
}
return _array1;
}
I then find myself doing things like:
-(NSMutableArray *)array1{
if (!_array1){
_array1 = [[NSMutableArray alloc] init];
// read a file
// [_array addObject:newObject];
}
return _array1;
}
It is and it isn't. Lazy instantiation is fine as a concept, but you have to be careful. For example, if two different threads attempt to access either of your variables at the same time, you may end up with having two different lazily instantiated variables. See the answer here:
Thread safe lazy initialization on iOS
Doing lazy loading for everything, may cause runtime slow down of user-interaction because the app may get busy every now and then to load stuff into memory. Use it only when required (i.e. when an object requires lot of memory in for complete loading.. )

ios alloc-release

My app is receiving memory warnings because it's asking for lot of memory. I try to release every allocation. However, sometimes I don't know how to do it.
For example: I have two pairs of .h and .m file. One of them makes connections with a server and the other with local SQLite.
Usually, the code which calls to a method from those files are like this:
-(NSMutableArray *) getRecentActivity{
LocalStorageController *local = [[LocalStorageController alloc]init];
return [local getRecentActivity];
}
getRecentActivity returns a NSMutableArray.
Well, in that piece of code we can see that I am allocating memory for the LocalStorageController but I never call to the release method so, I suppose, the more I call that function, the more memory I will be allocating.
If I call autorelease after init, it will crash.
Moreover, usually, I use this other kind of code:
ServerConnection *serv = [[ServerConnection alloc]init];
NSMutableArray list = [serv getMyListOfContacts];
Which uses ASIHTTPRequest and, if I call [serv release]; after the second line, the app crashes with EXC_BAD_ACCESS pointing to a line in ASIHTTPRequest library.
How is suppose to manage this situation?
Thank you very much!
The first case is easy;
-(NSMutableArray *) getRecentActivity{
LocalStorageController *local = [[LocalStorageController alloc]init];
NSMutableArray *tmp = [local getRecentActivity];
[local release];
return tmp;
}
The second case is hard to solve in a general way without seeing more of the actual code.
Using serv as a property would be fixing this retain/release problem.
In your .h:
#property (nonatomic, retain) ServerConnection *server;
In your .m:
#synthesize server;
- (void)dealloc {
[server release];
// The rest of your releases here...
[super dealloc];
}
- (void)yourMethod {
ServerConnection *myServConnection = [[ServerConnection alloc] init];
self.serv = myServConnection;
[myServConnection release];
NSMutableArray list = [self.serv getMyListOfContacts];
}
Just keep on using self.serv in this class from that point on and you won't have a problem with having the object being released.

Does the iOS SDK provide queues and stacks?

I'm writing an iPhone app, and I'm surprised that there seem to be no NSQueue or NSStack classes in Apple's Foundation Framework. I see that it would be quite easy to roll my own, starting with an NSMutableArray, so I'll do that unless I've missed something. Have I missed something?
Here's my Stack class, in case it's useful to those who come after me. As you can see, the pop method involves enough code that you'd want to factor it out.
Stack.h:
#import <Foundation/Foundation.h>
#interface Stack : NSObject {
NSMutableArray *contents;
}
- (void)push:(id)object;
- (id)pop;
#end
Stack.m
#import "Stack.h"
#implementation Stack
// superclass overrides
- (id)init {
if (self = [super init]) {
contents = [[NSMutableArray alloc] init];
}
return self;
}
- (void)dealloc {
[contents release];
[super dealloc];
}
// Stack methods
- (void)push:(id)object {
[contents addObject:object];
}
- (id)pop {
id returnObject = [[contents lastObject] retain];
if (returnObject) {
[contents removeLastObject];
}
return [returnObject autorelease];
}
#end
as far as I know there is no generic class avaialbe. Try using the NSMutableArray, add via addObject and get first/last via objectAtIndex and removeObjectAtIndex.
Another easy way would be to extend NSMutableArray's capabilities by making use of Objective C's categories. You can do that by adding two files to your project:
NSMutableArray+Stack.h
#interface NSMutableArray (StackExtension)
- (void)push:(id)object;
- (id)pop;
#end
NSMutableArray+Stack.m
#import "NSMutableArray+Stack.h"
#implementation NSMutableArray (StackExtension)
- (void)push:(id)object {
[self addObject:object];
}
- (id)pop {
id lastObject = [self lastObject];
[self removeLastObject];
return lastObject;
}
#end
Now you can use a regular NSMutableArray in every other file of your project like a stack and call push or pop on that object. Don't forget to #import NSMutableArray+Stack.h in those files. Here is some sample code how you can use your new NSMutableArray as a stack:
NSMutableArray *myStack = [[NSMutableArray alloc] init]; // stack size = 0
NSString *aString = #"hello world";
[myStack push:myString]; // stack size = 1
NSString *anotherString = #"hello universe";
[myStack push:anotherString]; // stack size = 2
NSString *topMostStackObject;
topMostStackObject = [myStack pop]; // stack size = 1
NSLog("%#",topMostStackObject);
topMostStackObject = [myStack pop]; // stack size = 0
NSLog("%#",topMostStackObject);
The log output will be:
hello universe
hello world
I'm a bit late to this party, but are you aware of CHDataStructures?
http://cocoaheads.byu.edu/code/CHDataStructures
I have put a working iOS Objective C queue object on GitHub. The code was taken from various posts and by no means is owned by me.
https://github.com/esromneb/ios-queue-object/
If you see any problems please fork, and make a pull request!
Yes, an NSMutableArray doubles as a stack or queue. (It would be slightly inefficient as a queue.)
You could also use C++'s stack and queue adapter, but it makes memory management a bit messy if you want to store Objective-C objects with it.
ObjectiveSugar is a very popular CocoaPod that provides, among a bunch of other great stuff, push and pop API calls on NSMutableArray. Sure, it's not in the iOS SDK, but I'm sharing it here because I was looking for the same thing, and this was the solution I went with (and it certainly didn't hurt that we were already using this CocoaPod in our codebase).
No. You missed nothing. That's all. Objective-C is higher level language look like C. Low level control is not required.
Cocoa classes are designed for easier use than efficiency. If you want to deal with performance, you have an option of raw C (or C++) implementation. Otherwise, just use easy way. Of course, early-optimization is evil.
If you want a kind of encapsulation, just make a new class which contains NSMutableArray within it. Hide inner NSMutableArray and just expose what you want. But you'll realize this is unnecessary.

Resources