Objective-c dynamically loading more UITableViewCells - objective-c

I am writing a iPhone app that calls a web service. Let say the web service returns 1000 elements in the json object. I don't want to load all 1000 of them since parsing can take some time. What I would like to do is load the first 15 elements of the NSDictionary that I created from the json object and then when the user scrolls to the bottom of the tableview have a 16th row that says "load more....". Since I already have all of the data stored in the NSDictionary object is there a way to break this up so that it returns the 15, then the user clicks "load more...." and it loads the next 15 and continues until there are no more elements in the NSDictionary? I can present examples of my code but I am wondering if anyone has an example of how to accomplish this. Thanks in advance for any assistance.

i think a UITableView does this for you. Only the visible cells are ever constructed. Their memory is then swapped with the next rows as you scroll down. I don't see a point in re-inventing the wheel.
Also as a note, only the visible cells are "parsed" as you put it. It will not construct a cell for every item in your datasource on load.

Assuming I hear you correctly I would say you just need a little tricky logic to get this working
I would simply maintain an index offset which I would multiply by the amount of rows you want to show at any time(15 in your case)
Your logic is to always return the amount of rows that you want to allow + 1 for the final. ex: return _indexOffset * 15 + 1; //for your numberOfRowsForSection
In your didSelectIndexPathOf you check if you're the last row:
if(indexPath.row == _indexOffset * 15)
{
_indexOffset ++;
[tableView reloadData];
}
This isn't an exact answer but I think it can get you started

Related

Linking Text to an Integer Objective C

The goal of this post is to find a more efficient way to create this method. Right now, as I start adding more and more values, I'm going to have a very messy and confusing app. Any help is appreciated!
I am making a workout app and assign an integer value to each workout. For example:
Where the number is exersiceInt:
01 is High Knees
02 is Jumping Jacks
03 is Jog in Place
etc.
I am making it so there is a feature to randomize the workout. To do this I am using this code:
-(IBAction) setWorkoutIntervals {
exerciseInt01 = 1 + (rand() %3);
exerciseInt02 = 1 + (rand() %3);
exerciseInt03 = 1 + (rand() %3);
}
So basically the workout intervals will first be a random workout (between high knees, jumping jacks, and jog in place). What I want to do is make a universal that defines the following so I don't have to continuously hard code everything.
Right now I have:
-(void) setLabelText {
if (exerciseInt01 == 1) {
exercise01Label.text = [NSString stringWithFormat:#"High Knees"];
}
if (exerciseInt01 == 2) {
exercise01Label.text = [NSString stringWithFormat:#"Jumping Jacks"];
}
if (exerciseInt01 == 3) {
exercise01Label.text = [NSString stringWithFormat:#"Jog in Place"];
}
}
I can already tell this about to get really messy once I start specifying images for each workout and start adding workouts. Additionally, my plan was to put the same code for exercise02Label, exercise03Label, etc. which would become extremely redundant and probably unnecessary.
What I'm thinking would be perfect if there would be someway to say
exercise01Label.text = exercise01Int; (I want to to say that the Label's text equals Jumping Jacks based on the current integer value)
How can I make it so I only have to state everything once and make the code less messy and less lengthy?
Three things for you to explore to make your code easier:
1. Count from zero
A number of things can be easier if you count from zero. A simple example is if your first exercise was numbered 0 then your random calculation would just be rand() % 3 (BTW look up uniform random number, there are much better ways to get a random number).
2. Learn about enumerations
An enumeration is a type with a set of named literal values. In (Objective-)C you can also think of them as just a collection of named integer values. For example you might declare:
typedef enum
{
HighKnees,
JumpingJacks,
JogInPlace,
ExerciseKindCount
} ExerciseCount;
Which declares ExerciseCount as a new type with 4 values. Each of these is equivalent to an integer, here HighKnees is equivalent to 0 and ExerciseKindCount to 3 - this should make you think of the first thing, count from zero...
3. Discover arrays
An array is an ordered collection of items where each item has an index - which is usually an integer or enumeration value. In (Objective-)C there are two basic kinds of arrays: C-style and object-style represented by NSArray and NSMutableArray. For example here is a simple C-style array:
NSString *gExerciseLabels[ExerciseKindCount] =
{ #"High Knees",
#"Jumping Jacks",
#"Jog in Place"
}
You've probably guessed by now, the first item of the above array has index 0, back to counting from zero...
Exploring these three things should quickly show you ways to simplify your code. Later you may wish to explore structures and objects.
HTH
A simple way to start is by putting the exercise names in an array. Then you can access the names by index. eg - exerciseNames[exerciseNumber]. You can also make the list of exercises in an array (of integers). So you would get; exerciseNames[exerciseTable[i]]; for example. Eventually you will want an object to define an exercise so that you can include images, videos, counts, durations etc.

Limiting NSTableView to two selections

I am wondering if anyone has a method to limiting the number of selections allowed in an NSTableView to 2 concurrent selections. I am trying to calculate the delta between two selected values and would like for it to only select two at a time.
I was thinking of trying to keep track of what has been selected so that I can programmatically unselect anything if the selection expands above two, but this seems kludgy and possibly not as easy as it sounds.
Implement the delegate method tableView:shouldSelectRow: and return NO if you don't think the user should be allowed to select the row. For any reason you decide - for instance because the number of selected rows is already 2.
To get the number of currently selected rows at any given time, just call selectedRowIndexes on the table view (not the delegate, nor data source). This will give you an NSIndexSet, which has a count method with the information you are looking for.
The index set also holds the information about the other row indexes already selected, in case you want to deselect them.
Not knowing anything about the app, the user experience sounds a bit... strange. It is easy enough to implement, though, so no harm done in trying it out.
In your Table View's delegate you can implement -[<NSTableViewDelegate> tableViewSelectionDidChange:(NSNotification *)]
Maybe something like this:
- (void)tableViewSelectionDidChange:(NSNotification *)notification
{
switch ([notification.object numberOfSelectedRows]) {
case 0: break; // Nothing is selected
case 1: break; // Only one row selected
case 2: break; // Two rows
default:
... unselect rows ...
break;
}
}
Of course you can also use an if statement. Maybe you also want to store in which order the rows are clicked—this could be done in the cases one and two.
Thank you both for coming up with something to help jog my brain into the right direction. I started exploring the NSTableViewDelegate a little bit more hoping to find something to help with this and re-read this method: tableView:shouldSelectRow and it allows me to permit or reject the row selection. So now I can simply reject selecting a third row provided I have 2 already selected:
- (BOOL)tableView:(NSTableView *)aTableView shouldSelectRow:(NSInteger)rowIndex
{
BOOL returnValue = YES;
if (_timeStampList.selectedRowIndexes.count >= 2)
returnValue = NO;
return returnValue;
}
I'll have to work on it some more to get exactly the behavior I want because with this small snippet it just rejects the user from selecting anything more; kind of abrupt about it too. So I'll probably add some more code to allow the user to select a new row while auto-un-selecting something else.
Thanks again!

Quartz Composer Objective C compare previous with current input

I'm trying to build something that will only fire a command once per keyboard input (as opposed to every frame like QC does natively). In order to do so, I'm trying to listen in on the keyboard inputs (via Freeboard) and compare the current input versus a previous version.
What seems to be happening is the previous version is getting wiped every time the patch executes, so my conditional to compare strings is failing every time. Here's some code to make it a bit clearer:
- (BOOL)execute:(id <QCPlugInContext>)context atTime:(NSTimeInterval)time withArguments:(NSDictionary *)arguments
{
self.outputPrevious=previousCharacter;
if ([self.inputCharacter caseInsensitiveCompare:previousCharacter]){
self.outputText=#"SAME";
}
else {
self.outputText=#"CHANGE";
}
previousCharacter = [NSString stringWithString:self.inputCharacter];
[previousCharacter retain];
return YES;
}
where self.outputText is the text that tells me the result of the if, self.outputPrevious is telling me what the previous character input was, and self.inputCharacter is the current keyboard input.
previousCharacter is defined in the header and instantiated in -init, so it shouldn't be being reset every time.
I've tried pretty much everything with this, so if you have any ideas or insights, that would be awesome. Thanks!
Figured it out eventually. Full solution can be found here

Advice how to present calculation of #records

I have an app that have a lot of records that i am loading into a core data DB. The actual loading is done in a module called "loadDBRecords". This module is called from "MainViewController", which is connected to "MainViewController.xib".
As the loading takes quite some time i have added an UIActivityIndicatorView to the .xib during the load. However, i would like to use a UIProgressView. When i look at this i do not see any way of using that unless i move the loading code from "loadDBRecords" to the "MainViewController".
My question is: What is the best way of leveraging the UIProgressView with my setup?
You could add a "progressHandler" block to the -loadDBRecords method. Execute the block for every record you load, and pass back a floating-point value between 0.0 and 1.0 indicating the progress thus far. The block can then assign that value to the progress bar, or print it to the console, or whatever you need it to do. (Traditionally, this would be done with a function pointer or a delegate/selector combination, but I've found blocks tend to make your intent clearer—or at least make it easier to show your intent.)
- (void)loadDBRecords:(void (^)(CGFloat progress))progressHandler {
NSUInteger count = /* number of records*/;
for (NSUInteger i = 0; i < count; i++) {
/* load the record */
progressHandler((CGFloat)n / (CGFloat)count);
}
}

How to properly return a value from a method and have it available immediately after application loads?

first post here so sorry for the length of it. I've been lurking and learning a lot so far but now I have to step in and ask a question. I have read numerous posts here as advised in the FAQs, but I couldn’t find exactly the answer I’m looking for.
Before anything else, let me just say that I'm a total beginner in programming (let alone Objective-C) so please excuse me for any misuse of the terminology. Same goes for any funny english as english not my native language.
I'm building an unit conversion application with a main window containing (among other stuff) two popUpButtons. I'm using indexOfSelectedItem from both popUpButtons in order to calculate a float value (I'm getting the indexes initially in the AwakeFromNib and later in the pop up buttons controller method, when the user change selection).
My problem consists of two parts: first, the code for calculation of that float is pretty massive as I'm comparing every combination of the two indexes of selected items. And second, I would need to have the calculated float value available immediately after launch as the user might want to perform a conversion before using any of the window popUpButtons (otherwise I would put the calculation code in a -(IBAction) method).
So, I'm trying with the following code for calculation of the float value:
#interface MyClass: NSObject
float calculatedFloat;
-(void)setCalculatedFloat:(float)calcFl;
-(float)calculatedFloat;
#implementation MyClass
-(void)setCalculatedFloat:(float)calcFl {
calcFl = 1.0; // I'm simplifying, this is where I'd like to perform calculation
}
-(float)calculatedFloat {
return calculatedFloat;
}
Now, for the first part of my problem, when I use the calculatedFloat in another method, say:
-(void)printIt {
NSLog(#"Calculated float equals: %.2f", calulatedFloat);
}
all I receive in Debugger is 0.00.
First question would be: if this is not working, how do I properly access this value from within another method?
For the second part of the problem, I'm using -(void)AwakeFromNib; to set up popUpButtons etc. right after the launch but I really wouldn't like to put all of the float calculation code in it only to repeat it somewhere else later.
So the second question would be: is this even possible what I'm trying to achieve? Further more, do I need to move this calculation code to another class? If so, how can I make that other class aware of the indexOfSelectedItem from a popUpButton?
Sorry for the lengthy post and possibly confusing and silly questions. I hope you didn't have to cringe your teeth too much while reading! :)
Thanks!
-(void)setCalculatedFloat:(float)calcFl {
calcFl = 1.0; // I'm simplifying, this is where I'd like to perform calculation
}
This doesn't show up when you print it later because you assigned to the variable holding the new value, not the variable for the value of the property. You need to assign to your calulatedFloat instance variable.
(You typo'ed that variable name, BTW.)
You should move the calculating into another method, and send yourself that message from awakeFromNib and from anywhere that needs to cause recalculation. That method should call setCalculatedFloat: with the calculated value—i.e., setCalculatedFloat: should be just a simple setter. Once you make that change, you could replace your custom accessors with a #synthesize statement and let the compiler write the accessors for you.
My problem consists of two parts: first, the code for calculation of that float is pretty massive as I'm comparing every combination of the two indexes of selected items.
You might see whether you can create custom objects to set as the menu items' representedObject properties, in order to cut out this massive comparison tree. It's hard to be more specific about this without knowing what your comparison tree does.