How to display Summation in TableView in iPhone SDK? - iphone

Is it possible to display information in TableView as given in screenshot?
Here: 'MyFund' is sum of amounts of Rob, Mike and Sam Fund.
I am not sure how will I sum up the amounts and display in Table headers.
Please help!

Hmm. I suppose you could calculate the summation in sectionIndexTitlesForTableView as such:
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
// replace the following with however you'll calculate the sums
int sumSectionOne = 4;
int sumSectionTwo = 3;
return [NSArray arrayWithObjects:[NSString stringWithFormat:#"$%d",sumSectionOne], [NSString stringWithFormat:#"$%d",sumSectionTwo], nil];
}
but it does mean you'll be invoking reloadSections a lot on that table view. Moreover, this isn't entirely the intended purpose of UITableView (though admittedly a really easy way of doing this).

There is no sort cut for this you need to implement a good store data structre then a logic to fetch them.so its all about logic,see my approach.
You need to add this record in an array with dictionary form,means add fund with money in a dictionary with two different key says "fund" and "money"(any thing).
when you make section means in titleForHeaderInSection method, you need to implement the logic.you need to make loop upto array count and access the dictionaries and add all "money" values.
Now you need to implement.if you have face any problem in code then again ask.

Related

What will be the size(memory)of NSMutableArray?

I am parsing json data,and i store them into an NSMutableArray.
For each data,parameters are as the following format,
{
"id":"6",
"username":"biju",
"password":"biju123",
"usertype":"2",
"first_name":"biju",
"last_name":null,
"email":"b#b.com",
"blocked":"N",
"created":"2012-11-02 16:03:19",
"image":"http:\/\/192.168.1.254\/eatthos\/assets\/upload\/users\/1351852399_thumb.jpg","thumb_image":"1351852399_thumb.jpg",
"menu_image":"0",
"thumb_menu_image":"0",
"city":"njdfh",
"favorite_food":"kafh",
"favorite_restaurant":"kafdhj",
"phone_number":"0",
"description":"0",
"token":"Dwx0DG",
"fb_unique_id":null,
"account_type":"normal",
"twitter_id":null,
"followers":"5",
"follow":"N"
}
i am parsing about 100K of data,what will be the size(memory) of that array ?
Will it be a memory issue if i use it for an iphone app ?
You can try to find out size of your array with the following piece of code :
size_t total;
id obj;
for (obj in array)
{
total += class_getInstanceSize([obj class]);
}
NSLog(#"Array size : %ld",total); //This will return you size in bytes
you need to do : #import <objc/runtime.h>
The array itself won't take that much space -- it's just a bunch of pointers. An array with tens of thousands of items can still only be a few dozen kilobytes. The space taken by the objects that the array contains is likely to be much more significant. But that is something only you can see -- there is no "size of an object in an array." It's like asking "How big is a ball?" It is possible that your data's space needs are problematic, and it's equally possible that there's no problem at all. As with many programming questions, I think the best answer is to try and see for yourself.
Why can not you download 100 records each time like an apps then are in app store
So, That the app will load quicker that before
If u want to see the flow of the memory you can go through this link http://mobileorchard.com/find-iphone-memory-leaks-a-leaks-tool-tutorial/

NSMutableArray Difficulty

If you wanna see the code Im having problem with, here is the link:
Code
My question is connected with my past question.
I'm really having problem with my NSMutableArray, I'm currently using iCarousel for my slotMachine object(slot1 and slot2). My app works this way:
From PhotoViewController I made a view that has thumbnail images, then assign its frame with button. So if 1 image was pressed, it will save that integer via NSUserDefaults.
Then I will retrieve it in my carouselViewController
Im thinking of adjusting the array but I can't.
I also have tried my question here:
Comparing with NSMutableArray
If only I can do it the same as Array 2 it would be much easy, but still not working.
(ADDITIONAL INFO:)
I have done it this way, have a Viewcontroller that contains the UIImageView with a button in it, so when the user taps it, my CustomPicker pops up. My CustomPicker contains the image on what the user have picked on the camera roll. So each button has a specific value sent to my iCarouselView using NSUserDefaults. carousel1 for First slot and carousel2 for Second slot.
Here is what I wanna do: I want to forcefully make it stop to the index the user picks. (Which Im doing in my carouselDidEndScrollingAnimtaion)
In my carouselDidEndScrollingAnimation method i tested all of my condition(individually) it works perfectly in terms of comparing.
Then when I combine the conditions, the first Two comparison or STOP is RIGHT, but the next two are always wrong. Or sometimes Got mixed up.
I need to scroll the two specific indexes/integer which was User Picked( I already done that) was able to scroll 2 pairs of them but then the next two were always wrong because I think there indexes were adjusting.
PICTURES:
Image Below is my PhotoViewController which contained the Comparing Stage SETTING of my game.UIImageVIew with UIButton.Image that will be put in the number according to it will be Forcefully and should be forcefully shown.
When my iCarousel start then it stops for example in the image below(Which is not the same as the above):
Will be forcefully scroll to the inputted image in the PhotoViewController
Into:
Summary:
Its like this. I have a settingsView from there, I will import my images(Multiple) for Slot1 & Slot2.
Then in another View the PhotoViewController that is where the image above is shown. THe first column corresponds to 1st slot followed by the 2nd slot. if a view is pressed (for example No. 1 of Slot 1 it will load a thumbnail of images loading the images picked from Picker for the Slot 1.
You will have to do it 4 times(pair) ----> The displayed here I get their indexes via NSUserDefaults via button.tag then send to iCarouselView.
Then when you are done (pressed Done button) it will go to iCarouselView then, as shown above thats the view of it.
When pressed it will spin for couple of seconds, then when finished but not stop at the user picked in the PhotoView it will forcefully scroll to that index.
QUESTION:
Is there a way to make my array or my iCarousel.view not adjust their indexes when Im deleting. To still retain my indexes the right way. Or are there other solution like adjusting my array, the same as adjusting my PhotoViewController picked indexes too. Because I think that when my array retain their indexes even deleting I would be able to solve this problem. But still can't.
Hope you understand my question.
Is there a way to make my array or my iCarousel.view not adjust their indexes when Im deleting. To still retain my indexes the right way. Or are there other solution like adjusting my array, the same as adjusting my PhotoViewController picked indexes too. Because I think that when my array retain their indexes even deleting I would be able to solve this problem. But still can't.
The only way you have to modify the way iCarousel manages its indexes is by modifying the code. Indeed, if you look at the removeViewAtIndex method in iCarousel.m, you will see that indexes are managed through an NSDictionary, and at the moment of deleting, the dictionary is rearranged (items are reordered). You could take that method:
- (void)removeViewAtIndex:(NSInteger)index
{
NSMutableDictionary *newItemViews = [NSMutableDictionary dictionaryWithCapacity:[itemViews count] - 1];
for (NSNumber *number in [self indexesForVisibleItems])
{
NSInteger i = [number integerValue];
if (i < index)
{
[newItemViews setObject:[itemViews objectForKey:number] forKey:number];
}
else if (i > index)
{
[newItemViews setObject:[itemViews objectForKey:number] forKey:[NSNumber numberWithInteger:i - 1]];
}
}
self.itemViews = newItemViews;
}
You could apply the same logic to your array, so that the carousel and your array keep in sync. Of course, if you store the indexes somewhere (slot1/slot2/slot2/slot4?), you should also update their values after removing an element.
On the other hand, I think that what you are asking here is how to do something that you believe would solve the problem you have, but you are not really explaining what the problem is. Indeed, if I understand you correctly, what you do is:
spinning the carousel;
when the carousel stops, if it is not by chance on the desired item, you "force" it to scroll to that item.
There is no reason why this should not work after deleting some elements (unless iCarousel has some bugs, then the solution would be catching the bug). The only part is knowing which index is the one you would like to move to.
As a suggestion, I would start off by simplifying your delegate carouselDidEndScrollingAnimation method. Indeed, your carouselDidEndScrollingAnimation has a parameter called carousel, well, I think this is the only carousel you should ever be referring to in that method. If you don't see it, this is the reasoning: each of your carousel will stop scrolling and the carouselDidEndScrollingAnimation will be called; so that method will be called twice. Each time that method is executed you will modify the state of both carousel1 and carousel2 (by calling scrollToItemAtIndex); therefore, on each carousel you will call scrollToItemAtIndex twice.
This does no sound very correct to me. So you should find a way to scroll only carousel1 when carouselDidEndScrollingAnimation is called for carousel1 and to scroll only carousel2 when carouselDidEndScrollingAnimation is called for carousel2.
More generally, another point I would like to raise is that the idea of:
letting a carousel stop;
scrolling it again so that it reaches the desired position;
does not seem the best implementation possible since the user would see the carousel stopping and then starting over again.
The way I would approach this is by modifying directly iCarousel implementation so that it supports this specific behavior you need.
Concretely, give a look at the step method in iCarousel.m. This is called at each frame to produce the carousel animation. Now, in this method there is decelerating branch:
else if (decelerating)
{
CGFloat time = fminf(scrollDuration, currentTime - startTime);
CGFloat acceleration = -startVelocity/scrollDuration;
CGFloat distance = startVelocity * time + 0.5f * acceleration * powf(time, 2.0f);
scrollOffset = startOffset + distance;
[self didScroll];
if (time == (CGFloat)scrollDuration)
{
decelerating = NO;
if ([delegate respondsToSelector:#selector(carouselDidEndDecelerating:)])
{
[delegate carouselDidEndDecelerating:self];
}
if (scrollToItemBoundary || (scrollOffset - [self clampedOffset:scrollOffset]) != 0.0f)
{
if (fabsf(scrollOffset/itemWidth - self.currentItemIndex) < 0.01f)
{
//call scroll to trigger events for legacy support reasons
//even though technically we don't need to scroll at all
[self scrollToItemAtIndex:self.currentItemIndex duration:0.01];
}
else
{
[self scrollToItemAtIndex:self.currentItemIndex animated:YES];
}
}
else
{
CGFloat difference = (CGFloat)self.currentItemIndex - scrollOffset/itemWidth;
if (difference > 0.5)
{
difference = difference - 1.0f;
}
else if (difference < -0.5)
{
difference = 1.0 + difference;
}
toggleTime = currentTime - MAX_TOGGLE_DURATION * fabsf(difference);
toggle = fmaxf(-1.0f, fminf(1.0f, -difference));
}
}
}
and you see that when the carousel stops decelerating, it is scrolled again. This is exactly the same as you are doing, so you might find a way to modify this code and have the carousel scrolls exactly to the index you need. In this way you would get a far smoother spinning of the carousel.
Hope this helps and apologies for the lengthy reply.
Its a little difficult to know what the issue is here. Are you using a single NSMutableArray for the images and using the NSUserDefaults value to get the object at the index in the array?
Im not 100% sure on what is happening. What does the user do(and in what view) and what is triggered after that(which view is presented).
Are you trying to stop the "spinning" images on the image that is the same as the one picked from the previous view?
According to your images above, the images are off by a single index. Is this the case every time? Maybe there is an issue with your fetching from the array.
If you give me some more info I can help.
I looked through the code you pasted again and I think this might be your issue
if (twoSlot1 > [(UIImageView*)[self.carousel2 currentItemView] tag]){
[self.carousel1 scrollToItemAtIndex:(-twoSlot1)-2 duration: 3.5f];
} else {
[self.carousel1 scrollToItemAtIndex:-twoSlot1 duration: 3.5f];
}
On all other code blocks like that you have this where you call each carousel. In the above code you call carousel 1 twice.
if (slot2 > [(UIImageView*)[self.carousel1 currentItemView] tag]){
[self.carousel1 scrollToItemAtIndex:(-slot2)-2 duration: 3.0f];
} else {
[self.carousel1 scrollToItemAtIndex:-slot2 duration: 3.0f];
}
if (twoSlot2 > [(UIImageView*)[self.carousel2 currentItemView] tag]){
[self.carousel2 scrollToItemAtIndex:(-twoSlot2)-2 duration: 3.5f];
} else {
[self.carousel2 scrollToItemAtIndex:-twoSlot2 duration: 3.5f];
}
You call self.carousel1 when you should be calling number 2.
Is this correct?
Referring to your question. You want an array that does not change its members' indexes when a member is deleted from the array.
I guess you could use an NSMutableDictionary. It is an associative array so to say, where the indexes are of your choice and they remain unchanged when you delete a member from in between.
You may still use 0..n as your Index. You can still use some methods that you are familiar with from NSArray, such as count. You can use an enumerator to go through all members of the dictionary. On the other hand you can still use your for-loops as you are used to use them with arrays. Just be prepared that a) objectForKey:i may return nil if the key/index does not exist (e.g. was deleted) and that count retuns the number of the objects but not the highest index+1 as it does with arrays.
Not sure if I understand completely, but when one of the elements in your mutable array is deleted, rather than just deleting it, maybe insert it with another "dummy" place holder object? That way your indexes won't change at all when a delete occurs
I'm having a hard time understanding your overall problem, but from what I can gather the crux of your question is this:
Is there a way to make my array or my iCarousel.view not adjust their indexes when Im deleting.
I don't know whether it will solve your bigger issue, but using an NSMutableDictionary to simulate an array should allow you to do this. You can simply use the indices as the keys to the dictionary, and then when you remove the item associated with an index, no other indices will be adjusted as a result. For example:
NSMutableDictionary *arrayDict = [[NSMutableDictionary alloc] init];
[arrayDict setValue:foo forKey:[NSNumber numberWithInt:[arrayDict count]]];
[arrayDict setValue:bar forKey:[NSNumber numberWithInt:[arrayDict count]]];
[arrayDict setValue:fooBar forKey:[NSNumber numberWithInt:[arrayDict count]]];
And then you can access the object an at index with [arrayDict objectForKey:[NSNumber numberWithInt:index]].
Note that using an NSNumber for the key parameter of setValue:forKey: will generate a warning, but you can safely ignore this (or use the string representation if it bothers you).

sorting array containing arrays ios

I made a little program calculating gas consumption.
There is one view controller for each data entry necessary to calculate consumption in the final view controller.
So you enter the driven distance in the first controller, the gas fuelled up in the next controller. in the controller displaying the result, the current date is added, too.
All entries are stored in a plist file as strings for easier use with the tableviews later (except for the date).
Now I want to open this data in a summary view controller to populate a tableview.
Currently I have retrieve 3 arrays from the plist file (similar to the columns of a table):
array 1: NSDate
array 2: NSString representing a number
array 3: NSString representing a number
I know how to populate my tableview, but I cannot wrap my head around the sorting.
I tried changing the column approach into a table row based approach getting every single element from each of the arrays and adding them to a new array, containg each a date and two numbers (as strings).
I tried setting up sortdescriptors, I tried using selectors, but it seems I don't fully comprehend how to work it. Personally, I prefer examples, so I was looking for tutorials on this topic. The developer documentary didn't help that much.
I don't expect to get a complete example for this problem, but maybe some pointers on how to arrange my data and what best to use to sort the complete data array.
Thanks for any pointers or examples.
EDIT:
I finally got all "Table-lines" as "rows" into a dictionary. Now I can access the single columns by key for the column. And this also allows sorting the stringvalues in my array of dictionaries ascending or descending using a sortdescriptor.
This may not be the most elegant approach, but I think I now can do what I wanted.
Excuse the "Table" comparisons, but I find this easier to grasp.
If anyone has pointers to good array tutorials, I'd be more than thankful.
I'm not really clear on how you want to sort, but maybe you can adapt something from this (sorts an array of dictionaries each with a key #"row" with a value type NSNumber) -
First of all, make a comparison result function:
static NSComparisonResult compareRowNumbers(NSDictionary *dict1, NSDictionary *dict2, void * context) {
if ([[dict1 objectForKey:#"row"] intValue] < [[dict2 objectForKey:#"row"] intValue]) {return NSOrderedAscending;}
if ([[dict1 objectForKey:#"row"] intValue] > [[dict2 objectForKey:#"row"] intValue]) {return NSOrderedDescending;}
return NSOrderedSame;
}
Then you can use it like so -
NSMutableArray *myArray = [NSMutableArray array];
// populate your array with loads of stuff (in this case, NSDictionaries as decribed above)
// now sort it
[myArray sortUsingFunction:compareRowNumbers context:NULL];
...and your array is automagically sorted.

Detect the last element when using NSFastEnumeration?

Is it possible to detect the last item when using NSFastEnumeration?
for(NSString *str in someArray){
//Can I detect if I'm up to the last string?
}
Is it possible to detect the last item
when using NSFastEnumeration?
Not with 100% accuracy (or by limiting the array contents to being entirely unique pointers so that pointer comparison works as discussed in another question) without also doing a bunch of work that leads to just doing it the old way.
Note that if you can target 4.0+, you can use enumerateWithBlock: that gives both the item and the index. It is as fast or faster than fast enumeration, even.
I think the only way is the old fashioned way, something like:
NSUInteger count = [someArray count];
for (NSString *str in someArray) {
if (--count==0) {
//this is the last element
}
}
At the end of the loop, "str" will still be pointing to the last element. What is it you need to do?

What's the best approach to asynchronous image caching on the iPhone?

I'm creating an iPhone app that will pull data down from a Web API, including email addresses. I'd like to display an image associated with each email address in table cells, so I'm searching the Address Book for images and falling back on a default if the email address isn't in the book. This works great, but I have a few concerns:
Performance: The recipes I've found for looking for an address book record by Email address (or phone number) are reportedly rather slow. The reason for this is that one must iterate over every address book record, and for each one that has an image, iterate over all email addresses to find a match. This can be time-consuming for a large address book, of course.
Table Cells: So I thought I'd gather up all the email addresses for which I need to find images and find them all at once. This way I iterate through the book only once for all addresses. But this doesn't work well for table cells, where each cell corresponds to a single email address. I'd either have to gather all the images before displaying any cells (potentially slow), or have each cell look up each image as it loads (even slower, as I'd need to iterate through the book to find a match for each email address).
Asynchronous Lookup: So then I thought I'd look them up in bulk, but asynchronously, using NSInvocationOperation. For each image found in AddressBook, I'd save a thumbnail in the app sandbox. Then each cell could just reference this file and show the default if it doesn't exist (because it's not in the book or hasn't yet been found). If the image is later found in the asynchronous lookup, the next time the image needs to be displayed it would suddenly appear. This might work well for periodic regeneration of images (for when images have been changed in the address book, for example). But then for any given instance of my app, an image may not actually show up for a while.
Asynchronous Table Cell Lookup: Ideally, I'd use something like markjnet's asynchronous table cell updating to update table cells with an image once it has been downloaded. But for this to work, I'd have to spin off an NSInvocationOperation job for each cell as it's displayed and if the cached icon is missing from the sandbox. But then we're back to inefficiently iterating through the entire address book for each oneā€”and that can be a lot of them if you've just downloaded a whole bunch of new email addresses.
So my question is: How do others do this? I was fiddling with Tweetie2, and it looks like it updates displayed table cells asynchronously. I assume it's sending a separate HTTP request for every image it needs. If so, I imagine that searching the local address book by email address isn't any less efficient, so maybe that's the best approach? Just not worry about the performance issues associated with searching the address book?
If so, is saving a thumbnail image in the sandbox the best approach to caching? And if I wanted to create a new job to update all the thumbnails with any changes in the address book say once a day, what's the best approach to doing so?
How do the rest of you solve this sort of problem? Suggestions would be much appreciated!
Regardless of what strategy you use for the actual caching of images, I would only make one pass through the Address Book data each time you get a batch of email addresses, if possible. (And yes, I would do this asynchronously.)
Create an NSMutableDictionary which will serve as your in-memory cache for search results. Initialize this dictionary with each email address from the download as a key, with a sentinel as that key's value (such as [NSNull null]).
Next, iterate through each ABRecordRef in the Address Book, calling ABRecordCopyValue(record, kABPersonEmailProperty) and looping through the results in each ABMultiValue that is returned. If any of the email addresses are keys in your cache, set [NSNumber numberWithInt:ABRecordGetRecordId(record)] as the value of that key in your dictionary.
Using this dictionary as a lookup index, you can quickly obtain the images of ABRecordRefs for only the email addresses that you are currently displaying in your table view given the user's current scroll position, as suggested in hoopjones's answer. You can add an address book change listener to invalidate your cache, trigger another indexing operation, and then update the view, if your application needs that level of "up-to-date-ness".
I'd use the last method you listed (Asynchronous Table Cell Lookup) but only look images for the current records being displayed. I overload the UIScrollViewDelegate methods to find out when a user has stopped scrolling, and then only start making requests for the current visible cells.
Something like this (this is slightly modified from a tutorial I found on the web which I can't find now, apologies for not citing the author) :
- (void)loadContentForVisibleCells
{
NSArray *cells = [self.table visibleCells];
[cells retain];
for (int i = 0; i < [cells count]; i++)
{
// Go through each cell in the array and call its loadContent method if it responds to it.
AddressRecordTableCell *addressTableCell = (AddressRecordTableCell *)[[cells objectAtIndex: i] retain];
[addressTableCell loadImage];
[addressTableCell release];
addressTableCell = nil;
}
[cells release];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;
{
// Method is called when the decelerating comes to a stop.
// Pass visible cells to the cell loading function. If possible change
// scrollView to a pointer to your table cell to avoid compiler warnings
[self loadContentForVisibleCells];
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
{
if (!decelerate)
{
[self loadContentForVisibleCells];
}
}
Once you know what address records are currently visible, just doing a search for those (5 -7 records probably) will be lightning fast. Once you grab the image, just cache it in a dictionary so that you don't have to redo the request for the image later.
You seem to try to implement lazy images loading in UITableView.
there's a good example from Apple, I'm referencing it here :
Lazy load images in UITableView
FYI, I've released a free, powerful, and easy library for doing asynchronous image loading and fast file caching: HJ Managed Objects
http://www.markj.net/asynchronous-loading-caching-images-iphone-hjobjman/