Working with big numbers - iphone

I have a number like 12345678910111213 and I need to pass it from one method(cellForRow) to another(button action method). The simplest way which I used to use is to pass it through a button tag. In this case it is impossible(?). I can also create a property for it but what about encapsulation? I want to know really RIGHT(and preferably simple) way for doing things like that. Thanks in advance!

Well you can actually attach the value to the UIButton. When you have the value you want to pass and you have a reference to the button:
static char kMyObject;
objc_setAssociatedObject(myButton, &kMyObject, [NSNumber numberWithInt:myInt], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
On the other side, when you receive the action with the button as id:
- (void)myAction:(id)sender
{
UIButton *myButton = (UIButton*)sender;
NSNumber *number=objec_getAssociatedOject(myButton,&kMyObject);
}

You cannot pass it as a tag as Saad said. You can use NSDecimal numbers here.
#Saad cannot use double, as it will lose precision.

In this integer tag you can store a pointer (case of 32 bit address) to a class/structure/whatever what represents bigint.
For example:
UIButton *button = [UIButton ...];
button.tag = (int)[[MyBigInt alloc] initWithString:#"12131312312312312"];
after:
MyBigInt *bigInt = (MyBigInt *)button.tag;
...
[bigInt release];

I'm going to make some assumptions here, because I just when through something similar.
The UIButton with the action is in a UITableViewCell.
You have an underlying source for all your data (ie. An array with all your data in it).
You have easy access to your tableView.
First, you need to get the cell which contains the button:
UITableViewCell *cell = nil;
for (UIView *view = sender; view; view = view.superview) {
if ([view isKindOfClass:[UITableViewCell class]]) {
cell = (UITableViewCell *)view;
break;
}
}
Next, you need to get the indexRow for that cell:
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
Finally, you have to get access to your data:
ModelClass modelObject* obj = [self.data objectAtIndex:indexPath.row];
Now, you can make any changes you need to your model.

Related

iPhone - button in UITableViewCell does not change image

I'm trying to do some cell creation using Xcode 4.2 storyboarding, and using Interface Builder to create a custom cell. I get the cell created fine, and I have a button within it, I am trying to have it when I press the button, the image changes, however it does not seem to work. This is what I have
- (IBAction)sendToFavorites:(id)sender {
UITableViewCell *cell = (UITableViewCell *)[[sender superview] superview];
int row = [feedTableView indexPathForCell:cell].row;
NSLog(#"\"%#\" is FAVORITED", [[_allEntries objectAtIndex:row] articleTitle]);
if ([[_allEntries objectAtIndex:row] isFavorited]) {
NSLog(#"Unfavorite");
[[_allEntries objectAtIndex:row] setFavorite:NO];
[[sender imageView] setImage:[UIImage imageNamed:#"StarEmpty"]];
} else {
NSLog(#"Favorite");
[[_allEntries objectAtIndex:row] setFavorite:YES];
[[sender imageView] setImage:[UIImage imageNamed:#"StarFilled"]];
}
}
Any help would be appreciated.
You could try and refresh the content of the table view. I.e., calling reloadData on your table view after setting the new image associated to the cell.
As far as I understand from you code, you are trying to modify the cell content directly. Instead, this should happen through the dequeueReusableCellWithIdentifier mechanism that controls the redraw of a table. So, simply: modify your data source, and redraw the table.
Hope this helps.
Figured it out.
[sender setImage:[UIImage imageNamed:#"StarEmpty"] forState:UIControlStateNormal];
Can't set it alone, have to set it with a state, whether it is Highlighted, Normal, etc.

Customizing table cell in ABPeoplePickerNavigationController

I've spent some time searching for this answer on SO, but couldn't find it, so here goes:
I'm starting with an ABPeoplePickerNavigationController, and when a user taps a person, they'll be taken to an ABPersonViewController where they'll be able to select phone numbers and email addresses. After they're finished with the ABPersonViewController, they'll be taken back to the ABPeoplePickerNavigationController. Pretty simple stuff.
What I want is to add a detailLabel to the table cell they selected in ABPeoplePickerNavigationController after they chose a phone number or an email address. Something like "Email and phone number chosen" or "Phone number chosen".
Apple's documentation says:
You should not need to subclass these controllers; the expected way to modify their behavior is by your implementation of their delegate.
The delegate methods provided won't handle this. Is there any way to accomplish this without subclassing myself? And, if I do have to subclass ABPeoplePickerNavigationController, which method would I override to update the detailLabel?
Thanks!
This bit of code seems to work for me, it grabs the cell when the user selects a person and adds a check mark. I'm guessing you can tweak the cell in other ways at this point as well.
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person{
UIView *view = peoplePicker.topViewController.view;
UITableView *tableView = nil;
for(UIView *uv in view.subviews)
{
if([uv isKindOfClass:[UITableView class]])
{
tableView = (UITableView*)uv;
break;
}
}
if(tableView != nil)
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:[tableView indexPathForSelectedRow]];
if(cell.accessoryType == UITableViewCellAccessoryNone){
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else{
cell.accessoryType = UITableViewCellAccessoryNone;
}
[cell setSelected:NO animated:YES];
}
return NO;
}
I have idea of how to do it, i think it will be helpful to you , but never implemented like this.
First you have to go with custom table . For that table you can give all the contact names from your addressbook. you can use http://developer.apple.com/library/mac/#documentation/userexperience/Reference/AddressBook/Classes/ABAddressBook_Class/Reference/Reference.html
just go through it you can understand .
you have to use these methods.
1) - (NSArray *)people
you will get all people records into returned array. each record will have unique id , you have to retrieve it
ABRecord rec = [returnedArray objectAtIndex:0];
NSString *pid = rec.uniqueId
-(NSString *) uniqueId ( this is ABRecord property method )
once you got it you can retireve from your array what you want by using that recordid/ unique id .

UISwitch and UITableViewCell iOS4

Caveat: I have looked for the answer to my question and several come close, but I'm still missing something. Here is the scenario:
I want a way to create UITableViewCells that contain UISwitches dynamically at run time, based on the data in a table (which I can do). The problem becomes connecting the switches such that I can get their value when that view is changed (navigated away, closed, etc). I have tried to use the events UIControlEventValueChanged to be notified, but have failed to specify it correctly, because it dumps when that switch is tapped. Also, there doesn't seem to be any way to uniquely identify the switch so that if all the events are handled by a single routine (ideal), I can't tell them apart.
So...
If I have a UITableView:
#interface RootViewController : UITableViewController
{
UISwitch * autoLockSwitch;
}
#property (nonatomic, retain) UISwitch * autoLockSwitch;
-(void) switchFlipState: (id) sender;
#end
// the .m file:
#implementation RootViewController
// ...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * CellIdentifier = #"Cell";
int row = 0;
NSString * label = nil;
TableCellDef_t * cell_def = nil;
row = indexPath.row;
cell_def = &mainMenuTableCellsDef[ row ];
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
label = (NSString *) mainMenuTableCellsDef[indexPath.row].text;
[cell.textLabel setText:(NSString *) mainMenuItemStrings[ indexPath.row ]];
if (cell_def->isSpecial) // call special func/method to add switch et al to cell.
{
(*cell_def->isSpecial)(cell ); // add switch, button, etc.
}
else
{
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
}
}
and this is the 'special' function:
-(void) autoLockSpecialItem :(UITableViewCell *) cell
{
autoLockSwitch = [[[UISwitch alloc] initWithFrame:CGRectZero] autorelease];
[autoLockSwitch addTarget:self action:#selector(switchFlipState:) forControlEvents:UIControlEventValueChanged ];
[cell addSubview:autoLockSwitch];
cell.accessoryView = autoLockSwitch;
}
and finally:
-(void) switchFlipState: (id) sender
{
NSLog(#"FLIPPED");
}
==============================================================
Questions:
Why would it crash (bad selector) when the switch was tapped? I believe that my code follows all the example code that I have seen, but obviously something is wrong.
I cannot put a instance method into a table as a function pointer; and it doesn't seem to like a class method either. If I make it a 'C/C++' function, how do I get access to the class/instance member variables? That is, if I want to put a call to autoLockSpecialItem into a static table (or reasonable facsimile) such that I can get autoLockSwitch member variable? If I make it a class method and the autoLockSwitch var a static, will that be valid?
More simply: how do I connect the UIControlEventValueChanged to my view (I have tried and failed) and can I differentiate at runtime within the event handler which switch has changed?
Is there a better way? I cannot believe that I am the first person to have to solve this type of problem.
Apologies for the length, appreciation for attention and grateful for any and all help.
:bp:
Don't know about why your method isn't connected, but a simple way to "differentiate at runtime within the event handler which switch has changed" is to take the (id)sender given to your event handler, walk your tableview, and compare the sender to any switches, if present, in each table item. If that's too slow, a hash table connecting senders to table cells, or something like that, is a possible optimization.
If you want to use C function pointers, you need to pass the object to the function to use it to call the object's property accessor methods within the function. (Or you could assign the object to a global variable if it's clearly a singleton, but that's a very politically incorrect answer.)
First, and easy way to define your different switches would be defining their tag based on the row number. When one of the switches is tapped you can access sender.tag to get the row number this way.
Also, you should probably be adding the switch the the cells content view, not the actual cell, [cell.contentView addSubview:autoLockSwitch]. Also the frame does need to be set (note CGRectZero, cocoa will ignore the width and height but uses the x,y coords to define where you want the switch in the cell.

I have a UISwtch embedded in a UITableViewCell defined in a XIB file. How can I respond to a change to the switch state?

I built the cell with Interface Builder. I load the cells like this:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"MassCircleNGTableCell" owner: self options: nil];
cell = circleNGCell;
self.circleNGCell = nil;
}
UISwitch *s = (UISwitch*)[cell.contentView viewWithTag: 20];
UILabel *label = (UILabel*)[cell.contentView viewWithTag:19];
label.text = #"some useful text";
And that part works, I get my table with custom cells. But, although I can set the initial state, I don't know how to respond to the user flipping the switch! I tried this:
[leftSwitch addTarget:self action:#selector(setCircle) forControlEvents:UIControlEventTouchUpInside];
But the app crashes with "[MassCircleNGViewController setCircle]: unrecognized selector sent to instance 0xdd024b0'"
Any ideas out there?
[Added Later (as requested)]:
// implementation of [MassCircleNGViewController setCircle] really just a stub here
- (IBAction) setCircle: (id) sender {
NSLog(#"setCircle sender == %#", (UISwitch*)sender);
}
The real problem was how I was trying to add the target. Need that colon after the selector name in the argument list!
[leftSwitch addTarget:self action:#selector(setCircle:) forControlEvents:UIControlEventValueChanged];
Okay, I found the problem. Where I had done this:
[leftSwitch addTarget:self action:#selector(setCircle) forControlEvents:UIControlEventTouchUpInside];
I needed to add a COLON after the selector name to get this:
[leftSwitch addTarget:self action:#selector(setCircle:) forControlEvents:UIControlEventTouchUpInside];
I know I saw a comment about doing that somewhere in these fora, but it took a couple of hours to sink in, and I have forgotten where I saw it. Oh, I did find a Very Nice Tutorial on XIB based custom UITableViewCells
here
There may be 1 of these problems:
1/ Do you have a method called setCircle inside your UITableViewCell, MassCircleNGViewController
2/ Double check all the release. Maybe your UITableViewCell is released when the method is invoked and another object in the same memory area now

iPhone - How to determine in which cell a button was pressed in a custom UITableViewCell

I currently have a UITableView that is populated with a custom UITableViewCell that is in a separate nib. In the cell, there are two buttons that are wired to actions in the custom cell class. When I click one of the buttons, I can call the proper method, but I need to know which row the button was pressed in. The tag property for each button is coming as 0. I don't need to know when the entire cell is selected, just when a particular button is pressed, so I need to know which row it is so I can update the proper object.
Much easier solution is to define your button callback with (id)sender and use that to dig out the table row index. Here's some sample code:
- (IBAction)buttonWasPressed:(id)sender
{
NSIndexPath *indexPath =
[self.myTableView
indexPathForCell:(UITableViewCell *)[[sender superview] superview]];
NSUInteger row = indexPath.row;
// Do something with row index
}
Most likely you used that same row index to create/fill the cell, so it should be trivial to identify what your button should now do. No need to play with tags and try to keep them in order!
Clarification: if you currently use -(IBAction)buttonWasPressed; just redefine it as -(IBAction)buttonWasPressed:(id)sender; The additional callback argument is there, no need to do anything extra to get it. Also remember to reconnect your button to new callback in Interface Builder!
You could use the tag property on the button to specify which row the button was created in, if you're not using tags for anything else.
For a implementation that is not dependent on tags or the view hierarchy do the following
- (void)btnPressed:(id)sender event:(id)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchPoint = [touch locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:touchPoint];
}
I have the same scenario. To achieve this, I derived a custom cell. I added two properties, section and row. I also added an owner, which would be my derived TableViewController class. When the cells are being asked for, I set the section/row based on the indexPath, along with the owner.
cell.section = indexPath.section
cell.row = indexPath.row
cell.owner = self
The next thing that I did was when I created the buttons, I associate the button events with the cell rather than with the tableViewController. The event handler can read the section and row entry and send the appropriate message (or event) to the TableViewController. This greatly simplifies house keeping and maintenance by leveraging existing methods and housekeeping and keeping the cell as self contained as possible. Since the system keeps track of cells already, why do it twice!
Even easier:
-(IBAction) buttonPressed {
NSIndexPath *myIndexPath = [(UITableView *)self.superview indexPathForCell: self];
// do whatever you need to do with the information
}
Here's a Swift example...
The UIControl class is the superclass of various iOS widgets, including UIButton, because UIControl provides the target/action mechanism that sends out the event notifications. Therefore a generic way to handle this is as follows:
func actionHandler(control: UIControl)
var indexPath = tableView.indexPathForCell(control.superview!.superview! as UITableViewCell)!
var row = indexPath.row
}
Here's an example of setting up a button control to deliver the action. Alternatively, create an #IBAction and create the action visually with Interface Builder.
button.addTarget(self, action: "actionHandler:", forControlEvents: .TouchUpInside)
You can downcast UIControl parameter to UIButton, UIStepper, etc... as necessary. For example:
var button = control as UIButton
The superview of control is the UITableViewCell's contentView, whose subviews are the UIViews displayed in the cell (UIControl is a subclass of UIView). The superview of the content cell is the UITableViewCell itself. That's why this is a reliable mechanism and the superviews can be traversed with impunity.
You can access the buttons superview to get the UITableViewCell that contains your button, but if you just need the row number, you can use the tag property like the previous post deacribes.
There are multiple methods to fix the problem.
You can use the "tag" property
Give the value indexPath.row as the tag value for the button.
btn.tag = indexPath.row;
Then in the button function, you can easily access the tag value and it will be the index for the clicked button.
-(void)btnClicked:(id)sender
{
int index = [sender tag];
}
You can use the layer property
Add the indexPath as the value in the layer dictionary.
[[btn layer] setValue:indexPath forKey:#"indexPath"];
This indexPath is accessible from the button action function.
-(void)btnClicked:(id)sender
{
NSIndexPath *indexPath = [[sender layer] valueForKey:#"indexPath"];
int index = indexPath.row;
}
With this method you can pass multiple values to the button function just by adding new objects in the dictionary with different keys.
[btnFavroite setAccessibilityValue:[NSString stringWithFormat:#"%d",indexPath.row]];
[btnFavroite setAccessibilityLabel:btnFavroite.titleLabel.text];
[btnFavroite addTarget:self action:#selector(btnFavClick:) forControlEvents:UIControlEventTouchUpInside];
-(void)btnFavClick:(id)sender{
UIButton *btn=(UIButton *)sender;
int index=[btn.accessibilityValue integerValue]]
}
this solution also works in IBAction connected using storyboard cell prototype
- (IBAction)viewMapPostsMarker:(UIButton*)sender{
// button > cellContentView > cellScrollView > cell
UITableViewCell *cell = (UITableViewCell *) sender.superview.superview.superview;
NSIndexPath *index = [self.mapPostsView indexPathForCell:cell];
NSLog(#" cell at index %d",index.row);
}