Unable to fetch data faster in cloudant DB - ios

I was using cloud ant Db for my iOS app with name tasks_master with almost 1000 documents. When I tried to fetch data from cloud ant it's taking almost 30 sec to fetch data i have tried with below code.
- (NSURL*) replicatorURL {
AppDelegate *app = [[UIApplication sharedApplication]delegate];
NSString *db_name = #"tasks_master";
NSString *url = [NSString stringWithFormat:#"https://%#:%##%#.cloudant.com/%#",
username,
password,
username,db_name];
return [NSURL URLWithString:url];
}
- (void) sync:(UIViewController *)sender {
[self pullReplication:sender];
[self pushReplication:sender];
}
-(void)pullReplication:(UIViewController *)sender {
[self log:#"Starting pull replication"];
NSURL *url = [self replicatorURL];
AppDelegate *delegate1 = (AppDelegate *)[[UIApplication sharedApplication] delegate];
CDTReplicatorFactory *factory = delegate1.replicatorFactory;
CDTReplicator *replicator = [factory onewaySourceURI:url targetDatastore:delegate1.datastore];
[self startAndFollowReplicator:replicator label:#"pull"];
}
- (void) pushReplication:(UIViewController *)sender {
[self log:#"Starting push replication"];
NSURL *url = [self replicatorURL];
AppDelegate *delegate1 = (AppDelegate *)[[UIApplication sharedApplication] delegate];
CDTReplicatorFactory *factory = delegate1.replicatorFactory;
CDTReplicator *replicator = [factory onewaySourceDatastore:delegate1.datastore targetURI:url];
[self startAndFollowReplicator:replicator label:#"push"];
}
when i call tasks
-(void)fetchtasks{
[[[CDTTodoReplicator alloc]init]sync];
self.indexManager = [[CDTIndexManager alloc] initWithDatastore:self.datastore
error:&error];
indexName= [self.datastore ensureIndexed:#[#"originator",#"members",#"meeting_status"] withName:#"meeting_index"];
query=#{#"$and":#[#{#"meeting_status":#"Scheduled"}, #{#"$or":#[#{#"originator":app.userName},#{#"members":app.userName}]}]};
result = [self.datastore find:query];
}
can any one help me out how to fetch data faster .

I've written a little helper class to cut down on some of the boiler plate for this kind of thing. It's the one used in the video referenced above.
Cloudant.h https://gist.github.com/xpqz/f8b304353080c3963a45
Cloudant.m https://gist.github.com/xpqz/62b5267c250f04c30f9b
When you add documents to a Cloudant database, they become available through the so called primary index, also known as All Docs. This can easily be checked with 'curl' from the command line, e.g.:
% curl https://skruger.cloudant.com/routes/_all_docs
Every document you store will appear in the returned data from the primary index.
Design documents are there for a different purpose - they define secondary indexes, called views, mostly written as little javascript functions that define a map-reduce operation to expose some facet of your data. Views allow you to index your documents in additional ways to the document id that you get for free.
You can create your own views directly by creating design documents yourself, but client software accessing the database sometimes also create design documents and views automatically which sometimes can be confusing when you see stuff appearing under _design that you didn't explicitly create.
In summary: every document appear in the primary index, _all_docs. Design documents are there to hold javascript functions used to generate secondary indexes, called views. These can be created explicitly, or generated automatically 'behind your back' by client software.
More info:
Primary index and all docs
Design documents and secondary indexes
Search indexes and Lucene
Stefan

Related

How to reinit AVPlayerItem?

I am initializing AVPlayerItem with "initWithUrl:" method.
Issue is that when initialization is interrupted (e.g. connection is lost)
Let's say we have following:
self.avPlayerItem = [[AVPlayerItem alloc] initWithUrl:url];
1.
What should be done? What happens to instance of avPlayerItem when connection is lost meanwhile?
Is there some protocol to implement in order to identify if initialization was successful or not?
2.
What I have noticed is that once initialization is interrupted then next "successful" initialization of avPlayerItem doesn't have tracks at all (they are present when no interruption is done before)
To initialize avPlayerItem with tracks again from the source user needs to close and open the app again.
When dealing with code that relies on internet connection you have to make sure there are failsafes that kick in when something goes wrong, because at some point it will.
What should be done?
1) Perform all code that relies on internet connection on a background thread. You don't want to block up the UI.
2) If possible verify the downloaded file before using.
There are different ways of going about this but off the top of my head I think I would use NSURLConnection or similar API to download the file into a temp folder. ON A BACKGROUND THREAD.
When downloaded I would initialise an AVAsset using the temp URL. AVAsset has some nice properties like playable that will help you check that the file downloaded OK. (NSURLConnectionDelegate also has a method that notifies if there was an error downloading.)
If you've got this far then you can create an AVPlayerItem with your AVAsset and away you go. Remember to wipe the contents of your temp folder at some point if you're not hanging on to the downloaded content.
Remember that you want to play your file on the main thread but all other loading and checking is probably best done on a background thread; you definitely want to use NSURLConnection from a background thread.
Store the AVPlayerItem in an NSPurgeableData object first, and play from that; store the data object in an NSCache object to automatically evict the object from memory after it has played, or when the connection is dropped, and the former AVPlayerItem is replaced by a new one (all of these things you should be doing anyway, regardless of the particular problem you describe). Here's some code to get you started:
void (^cachePlayerItem)(AVPlayerItem *, NSCache *, NSString *) = ^(AVPlayerItem *playerItem, NSCache *cache, NSString *key) {
NSURL *fileURL = [(AVURLAsset *)playerItem.asset URL];
NSPurgeableData *data = [NSPurgeableData dataWithContentsOfURL:fileURL];
[data beginContentAccess];
[cache setObject:data forKey:key];
[data endContentAccess];
[data discardContentIfPossible];
};
Put this block anywhere in an implementation file, defining it in the header file with:
typedef void (^cachePlayerItemBlock)(AVPlayerItem *, NSCache *, NSString *);
Call it within a method with:
cachePlayerItem(playerItem, playerItems, phAsset.localIdentifier);
Whereas, playerItem is the AVPlayerItem, playerItems is the NSCache cache, and, depending on what kind of asset from which you are acquiring the AVPlayerItem, an identifier of some kind unique to it (or, in the example above, its associated asset).
By the way, I set up my caches in AppDelegate accordingly:
- (NSCache *)thumbnailCache {
__block NSCache *t = self->_thumbnailCache;
if (!t) {
t = [[NSCache alloc] init];
[t setName:#"Thumbnail Cache"];
[t setEvictsObjectsWithDiscardedContent:TRUE];
[t setCountLimit:self.assetsFetchResults.count];
self->_thumbnailCache = t;
}
return t;
}
This ensures not only global access to, but also one instance of, the cache, which is particularly important when caching AVPlayerItems, as they can be large in size.
To create a globally accessible cache in AppDelegate, add these to your header and implementation files, respectively:
+ (AppDelegate *)sharedAppDelegate;
...and:
+ (AppDelegate *)sharedAppDelegate
{
return (AppDelegate *)[[UIApplication sharedApplication] delegate];
}
To reference the cache in other class files, import the AppDelegate header file, and, if desired, create a shortcut to the AppDelegate's sharedApplication method:
#import "AppDelegate.h"
#define AppDelegate ((AppDelegate *)[[UIApplication sharedApplication] delegate])
Insodoing, the cache can be referenced by...:
AppDelegate.thumbnailCache
...instead of:
AppDelegate.sharedAppDelegate.thumbnailCache

how to manage caching memory in AFNetworking Library

I am developing a content display app in which there is a table view and a detail view corresponding to each row in the table.
There are 12 categories in which content is loaded.
I have completed the app and it is working fine. Now I need to manage memory consumption for cache as I am receiving a warning at run time. I am using AFNetowking lib for caching.
There is no problem in functioning of the app. I just need to do some memory management and apply the code.
I am trying to allocate some particular memory and disk apace for each category.
following is the code that i am using to allocate ram and disk size for each category.
NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:15 * 512 * 1024
diskCapacity:10 * 1024 * 1024
diskPath:nil];
[NSURLCache setSharedURLCache:sharedCache];
xcode version : 6.1
taget ios version : 6.0
app : universal
I think the recommendation is to not set the size of the cache. The system should take care of that.
I would generally use a common NSCache, and just store data packets based on the URL. And then convert the data back into any image/xml/text whatever I was expecting.
// This should reference an NSCache instance
_contentCache = [[NSCache alloc] init];
// create a key for the request.
cacheKey = [NSString stringWithFormat:#"%#|%#",uri,body];
NSData *cacheData = [_contentCache objectForKey:cacheKey];
// if its in the cache, just return it.
if (cacheData) {
return cacheData;
}
// Request the data here and return it.
_contentCache is defined in the AppDelegate. So that I can reference it easily from across the app.
- (id) init {
_appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
_contentCache = [_appDelegate contentCache];
return self;
}
I've posted my class to GitHub. Its not complete, but its useable.
postmaster - GitHub

ios - Storing binary data 'externally' in coredata causes orphaned files

I'm not sure whether this is a bug or not, so am asking for advice...
(iOS 7.1.2 on xcode 5.1.1)
My app stores many large data image in coredata. The binary images have their attribute set in the entity to 'Allows External Storage', so I see a file (guid) appear in the _EXTERNAL_DATA sub-folder for my app.
During the lifetime of this app, the file will change regularly and so I overwrite the existing image and save the context.
The problem is, I'm seeing orphaned copies of my image files (guids) appearing, as new ones are created, but the old ones are not deleted.
This can be reproduced as follows...
Create a utility app with a 'test' button on it that utilises coredata, creating a simple entity...
Create the initial entity in the viewDidLoad, storing a reference to it....
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
id delegate = [[UIApplication sharedApplication]delegate];
NSManagedObjectContext *managedObjectContext = [delegate managedObjectContext];
// Create initial external file
_testEntity = [NSEntityDescription insertNewObjectForEntityForName:#"TestEntity" inManagedObjectContext:managedObjectContext];
UIImage *planeImage = [UIImage imageNamed:#"plane.jpg"];
_testEntity.image = [NSData dataWithData:UIImagePNGRepresentation(planeImage)];
[delegate saveContext];
}
Then in an action handler for a button on the view, simply change the image...
-(IBAction)onTestImageButton:(id)sender {
int randNum = rand() % 4 + 1;
id delegate = [[UIApplication sharedApplication]delegate];
// Store image - again
UIImage *planeImage = [UIImage imageNamed:[NSString stringWithFormat:#"plane %d.jpg", randNum]];
_testEntity.image = [NSData dataWithData:UIImagePNGRepresentation(planeImage)];
[delegate saveContext]; }
Here, I have four large jpg's of a plane, each one slightly different size. (If they are the same size, the problem doesn't manifest itself)
Run the app and press the 'test' button several times. Soon, several versions of the file appear in _EXTERNAL_DATA
I would only ever expect there to be one version. Images are now orphaned and if a parent entity deletes this one via cascade delete rules, files are left behind, which take valuable space!
Is this a bug, or am I doing something wrong?
Thanks

Does referencing an iOS app delegate in a block create a copy of the delegate object?

Consider the following example:
- (void)exampleFunction
{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
SomeClass *classObject = [[SomeClass alloc] init];
[classObject someFunctionThatDoesBackgroundWorkAndCallsACompletionBlock:^(NSDictionary *results) {
SomeNeatObject *object = appDelegate.someNeatObject;
[object doSomeNeatStuff:results];
}];
}
Making an assumption that the completion block is executed on the main/UI thread to avoid additional insanity, here's what I'm unsure of:
Does the appDelegate variable get copied onto the stack, as per normal block rules when referencing variables inside the block?
If yes to #1, is this a good / safe practice? I could see this possibly causing problems if you did this in a block that was subsequently dispatched to a GCD queue, as .someNeatObject could have changed state / gone to nil?
I realize that the appDelegate should not be overused, but it is useful for it to hold information about the current state of the application, such as Core Data-related objects if you use Apple's templates for initializing a Core Data stack (at least on iOS projects). That particular case (Core Data) has me concerned as much of that stack is not thread-safe nor is it a good idea to be copying it.
Thanks in advance.
Your example will not compile because delegate is not defined. I assume you mean "SomeNeatObject *object = appDelegate.someNeatObject;"
In this example, appDelegate is a variable, whose value will be captured by the block. It's no different than any other variable.
It's not unsafe, because [[UIApplication sharedApplication] delegate] always returns the same thing, unless you change the delegate, which you probably don't.
The fundamental concepts here are: appDelegate is a variable which points (or refers) to an object (or instance) of type AppDelegate. In an iOS app there is one such instance, which is returned by [[UIApplication sharedApplication] delegate]. If you create a reference to appDelegate inside a block, you are making a copy of the variable, not the object. So in your code's block:
SomeNeatObject *object = appDelegate.someNeatObject;
This is semantically the same as putting the following code in the block (casts omitted):
SomeNeatObject *object = [[UIApplication sharedApplication] delegate].someNeatObject;
The SomeNeatObjects being referred to are the same thing.
Slightly more advanced concept: any object has an address in memory (an integer, usually seen in hexadecimal). If two variables have the same hexadecimal value, they point to the same object. If they have different values, they point to different objects. In your example, appDelegate (outside block) and appDelegate (inside block) have the same value, therefore point to the same object.
If you were to do this:
AppDelegate * otherDelegate = [appDelegate copy];
Then you would be making a copy of the object pointed to by appDelegate. But don't do this, please.
It's retain count does get incremented. The remedy is to tag it with the __weak attribute:
- (void)exampleFunction {
__weak AppDelegate *weakDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
SomeClass *classObject = [[SomeClass alloc] init];
[classObject someFunctionThatDoesBackgroundWorkAndCallsACompletionBlock:^(NSDictionary *results) {
SomeNeatObject *object = weakDelegate.someNeatObject;
[object doSomeNeatStuff:results];
}];
}

Starting points for creating an application that allows a user to add items to two separate lists

I am firstly new to SO and new to iOS Development. I have completed the CS193P course on iTunes and am ready to tackle my first proper app. I have the prototype set up and just need some reference pointers on where to begin (need that confidence).
The premise of the app is to allow the user to add entries to 1 of 2 available lists; either a giving or a receiving list. The entries will include things like "Name of Event", "Name", "Date" etc. There will also be an option for the user to of course go through the lists and see the entries; I want to allow the user to choose whether they search by name, date or event.
I've got the prototype set up completely and I am just wondering if this kind of application would be somewhat considered similar to an Address Book? The user can add the name of the person (or select the name from contacts), etc.
Apologies for our outstandingly basic question here, but does anyone have any good reference points for essentially, creating a list of entires that get appended to a specific list. I have familiar with Modal View Controllers and the delegates; I'm basically wondering what I should use to "store" the entires the users add. Should I use Core Data or some other technique, etc?
Thanks!
Amit
Yes you have to use Core Data to store the entries. Otherwise whenever the user reopens the app all the entries will be gone.
I've been using NSKeyedArchivers to store lists.
http://developer.apple.com/library/ios/#documentation/cocoa/reference/foundation/Classes/NSKeyedArchiver_Class/Reference/Reference.html
Very easy to manage, and it can store, save, and retrieve all your data easily.
Example would be a list (NSMutableArray) of objects. Each object implements NSCoding and has the initWithCoder: and encodeWithCoder: functions.
e.g. (assuming the objects have a name and date property)
- (id) initWithCoder:(NSCoder *){
self = [super init];
if (self){
[self setName:[aDecoder decodeObjectForKey:#"name"]];
[self setDate:[aDecoder decodeObjectForKey:#"date"]];
}
return self;
}
- (void) encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:name forKey:#"name"];
[aCoder encodeObject:date forKey:#"date"];
}
Then you could simply have your NSMutableArray which you add these objects to, managed by something which has the following functions, and just call saveChanges on it:
- (NSString *) itemArchivePath{
NSArray *documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentsDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [documentDirectories objectAtIndex:0];
return [documentDirectory stringByAppendingPathComponent:#"myArchiveName.archive"];
}
- (BOOL) saveChanges{
NSString *path = [self itemArchivePath];
return [NSKeyedArchiver archiveRootObject:myList toFile:path];
}
With those two functions implemented, you can just call saveChanges.
And to Retrieve the list later after the next startup, in your manager's init:
- (id) init{
self = [super init];
if (self){
NSString *path = [self itemArchivePath];
myList = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
// If the array hadn't been saved previously, create a new empty one
if (!myList){
myList = [[NSMutableArray Alloc] init];
}
}
}
Your question is very general, so here is my general answer: I would recommend using Core Data to store the lists, and an NSFetchedResultsController to display them. I would also recommend you have a look at the free Sensible TableView framework, which I use regularly to automate tasks that are very similar to the one you have at hand.

Resources