Alright, so this is an extension to a question I asked last night. I have a little firmer grasp on how data can be passed between view controllers using various techniques. I wanted to go the MVC route, and creating a Singleton class seems the closest concept similar to MVC.
Basically I created a simple app with two View Controllers and a singleton class. I am trying to pass the value of a text field into a UILabel. For whatever reason it isn't working. This is what my code looks like.
ViewController.h
#import <UIKit/UIKit.h>
#import "Model.h"
#import "ViewController2.h"
#interface ViewController : UIViewController {
NSString *text2pass;
}
#property (weak, nonatomic) IBOutlet UITextField *tf;
#property (weak, nonatomic) IBOutlet UILabel *btn;
- (IBAction)go:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize tf = _tf;
#synthesize btn = _btn;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSString *tfstring = _tf.text;
NSLog(#"string = %#",tfstring);
}
- (void)viewDidUnload
{
[self setTf:nil];
[self setBtn:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (IBAction)go:(id)sender {
NSLog(#"btn pressed");
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
ViewController2 *vc2 = (ViewController2 *) [storyboard instantiateViewControllerWithIdentifier:#"home"];
text2pass = _tf.text;
[self passValues];
[self presentModalViewController:vc2 animated:YES];
}
-(void) passValues {
Model *model = [Model sharedModel];
model.passedText = text2pass;
}
#end
ViewController2.h
#import <UIKit/UIKit.h>
#import "ViewController.h"
#interface ViewController2 : UIViewController {
NSString *passedText;
}
#property (nonatomic)NSString *passedValue;
#property (weak, nonatomic) IBOutlet UILabel *lbl;
- (IBAction)back:(id)sender;
#end
ViewController2.m
#import "ViewController2.h"
#interface ViewController2 () {
NSString *passedtext;
}
#end
#implementation ViewController2
#synthesize lbl = _lbl;
#synthesize passedValue = _passedValue;
- (void)viewDidLoad
{
// do code stuff here
NSLog(#"passedText = %#",passedText);
_lbl.text = passedText;
[super viewDidLoad];
}
- (void)viewDidUnload
{
[self setLbl:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (IBAction)back:(id)sender {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
ViewController *vc = (ViewController *) [storyboard instantiateViewControllerWithIdentifier:#"welcome"];
[self presentModalViewController:vc animated:YES];
}
#end
Model.h
#import <Foundation/Foundation.h>
#interface Model : NSObject {
NSString *passedText;
}
#property (nonatomic, strong) NSString* passedText;
+ (Model *) sharedModel;
#end
Model.m
#import "Model.h"
#implementation Model
#synthesize passedText = _passedText;
static Model *sharedModel = nil;
+ (Model *) sharedModel {
#synchronized(self){
if (sharedModel == nil){
sharedModel = [[self alloc] init];
}
}
return sharedModel;
}
#end
The project can be downloaded in its entirety from here http://chrisrjones.com/files/KegCop-Test.zip
If you know why the UILabel is not displaying the text field text let me know. Oh I pretty much followed this -> http://www.youtube.com/watch?v=ZFGgMPcwYjg&feature=plcp
Your addressing, and memory management is just plain... off. Firstly, there's absolutely no reason to create a singleton for this, but that's beside the point here.
Secondly, when declaring properties, (atomic, assign) is defaulted to if not otherwise specified, which means your string:
#property (nonatomic)NSString *passedValue;
is weak sauce, ripe for deallocation and destruction at a moments notice. Declare it copy, strong, or retain.
Thirdly, there's absolutely no reference to your singleton in the pushed view controller, yet you seem to have the belief that objects that are named the same in different classes retain their value (especially when #import'ed). Not so. You need to reference your singleton and pull the value of [Model sharedModel].passedText into that text field.
In fact, I fixed your sample in two lines:
//ViewController2.m
#import "ViewController2.h"
//actually import the singleton for access later
#import "Model.h"
#interface ViewController2 () {
NSString *passedtext;
}
#end
#implementation ViewController2
#synthesize lbl = _lbl;
#synthesize passedValue = _passedValue;
- (void)viewDidLoad
{
// do code stuff here
NSLog(#"passedText = %#",passedText);
//actually reference the singleton this time
_lbl.text = [Model sharedModel].passedText;
[super viewDidLoad];
}
- (void)viewDidUnload
{
[self setLbl:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (IBAction)back:(id)sender {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
ViewController *vc = (ViewController *) [storyboard instantiateViewControllerWithIdentifier:#"welcome"];
[self presentModalViewController:vc animated:YES];
}
#end
Which yields this:
I wouldn't recommend using a Singleton as a good way to pass data around your application. Most apps are simple enough that this kind of central access is not necessary, and it usually creates a maintenance nightmare... but I don't think the fact that you're using a Singleton is actually important to getting your code working.
Assuming you have access to the data in ViewController1, in your case through the a Singleton instance of Model (which needs a more descriptive name), then all you have to do is pass through the data to ViewController2 when it is created and presented, which eliminates the need for a Singleton at all.
Once you create the controller, set the data you need, and then present the view controller - which is basically what you're doing anyway.
As to why it's not working: Is the view controller being presented, just not with the correct data? Or is there actually an issue presenting the controller at all? I would set a breakpoint in the go: action of ViewController1, make sure the data you expect is in the textfield, correctly populates the Model and that the value is correctly pulled out of the Model in ViewController2.
Unless you've removed some of the code, it looks like you correctly populate the Model property in ViewController1, but in ViewController2 you refer to a local ivar passedTextrather than pulling it from the model.
On a separate note, the way to go back from a presented modal view controller is usually to dismiss that controller, not to re-create the initial controller and present that over the top.
Related
I have a table view controller called StackViewController, this is where I hold a list of todo's that has been created in CreateViewController...
I have an NSString property in StackViewController called currentTarget that represent the first to do in the stack:
import <UIKit/UIKit.h>
#interface StackTableViewController : UITableViewController
#property (nonatomic, strong) NSString *currentTarget;
#end
This property holds the first NSString object in the table view, I get it like this:
#import "StackTableViewController.h"
#import "Target.h"
#import "CoreDataStack.h"
#interface StackTableViewController () <NSFetchedResultsControllerDelegate>
#property (nonatomic, strong) NSFetchedResultsController *fetchedResultController;
#end
#implementation StackTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.fetchedResultController performFetch:nil];
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
Target *target = [self.fetchedResultController objectAtIndexPath:indexPath];
self.currentTarget = target.body;
}
Now, when I log into my home page which called HomeViewController I want to initiate the StackTableViewController and get its currentTatget property value...
I know that there are delegate to help you notify other views when a change has happened, but in my case I want to get this property value before even I have been in this page (StackTableViewController), because the HomeViewController is the first view controller that is loaded (my initial view controller) and I what to access this property when I was just logged in to the app and populate a label with it.
How should I do this?
I thought maybe something like this:
#import "HomeViewController.h"
#import "CreateViewController.h"
#import "StackTableViewController.h"
#interface HomeViewController ()
#property (strong, nonatomic) IBOutlet UILabel *targetLabel;
#end
#implementation HomeViewController
- (void)viewDidLoad {
[super viewDidLoad];
StackTableViewController *vc = [[StackTableViewController alloc] init];
NSString *current = vc.currentTarget;
self.targetLabel.text = current;
}
But i'm missing something here...my label is not populated...
I think there is something with the views lifecycle.
i'm a newbie please help me to figure this out...thanks
Don't do anything to do with graphics in viewDidLoad. The earliest you want to do it is in viewWillAppear (most of the time) and occasionally you will need to do it in viewDidAppear.
Try the same code in viewWillAppear and it should work.
Oh right, since your other viewController is setup in viewDidLoad, you need to call
[stackTableViewController view] on your stackTableViewController after you alloc init it. Seems weird, but this actually works. This is because the StackTableViewController doesn't have its calculation done when you initialize it, it runs through it in it's viewDidLoad delegate.
- (void)viewDidLoad {
[super viewDidLoad];
StackTableViewController *vc = [[StackTableViewController alloc] init];
[vc view];
NSString *current = vc.currentTarget;
self.targetLabel.text = current;
}
I'm using a Split View Controller for an iPad app. I'm trying to send a label change to the detailReceiving Controller from the rootSending Controll when a button is pushed. I've read through tutorials on protocols and came up with the code below. When I click the button on rootSending, nothing happens to the label on detailReceiving. Do I have to do something else with a splitViewContoller so that the label will update? Shouldn't detailReceiving change the label when it receives the message?
rootSending.h
#import <UIKit/UIKit.h>
#protocol TestDelegate <NSObject>
-(void)tester:(NSString*)testString;
#end
#interface rootSending : UIViewController
#property (nonatomic, assign) id <TestDelegate> delegate;
#end
rootSending.m
#import "rootSending.h"
#implementation rootSending
#synthesize delegate;
-(void)viewDidLoad{
}
-(IBAction)buttonPressed:(id)sender{
[delegate tester:#"button pressed"];
}
#end
detailReceiving.m
#import "detailReceiving.h"
#import "rootSending.h"
#interface detailReceiving ()<TestDelegate>{
IBOutlet UILabel *label2;
}
#end
#implementation detailReceiving
-(void)viewDidLoad{
rootSending *obj = [rootSending alloc];
obj.delegate = self ;
}
-(void)tester:(NSString *)testString{
label2.text = testString;
}
#end
First of all, never ever have an alloc without an init! But in this case, even if you did use alloc/init, it still wouldn't work because that just creates a new instance of rootSending, not the one that you have in your split view. You need to get a reference to the one you have, which you can get from the split view controller,
-(void)viewDidLoad{
rootSending *obj = (rootSending *)self.splitViewController.viewControllers.firstObject;
obj.delegate = self;
}
After Edit:
If your mate controller is embedded in a navigation controller, then you need to get the navigation controller's topViewController to get your reference.
-(void)viewDidLoad{
UINavigationController *nav = (UINavigationController *)self.splitViewController.viewControllers.firstObject;
xmlListOfItems *obj = (xmlListOfItems *)nav.topViewController;
obj.delegate = self;
}
I have a VC of custom type LVSBBSettingsViewController for user settings. The VC is presented by a main menu in LVSMainViewController. The main VC sets the values of the controls in the settings VC programatically. However, when the settings view appears, the controls all revert to the values assigned to them in the storyboard.
I am using delegation to close the settings view and to pass data from the settings VC back to the main VC when it closes. But I don't think that's what's causing the problem since the same thing happens even if I remove that.
What's causing this? I have a feeling I'm missing something really simple here...
LVSBBSettingsViewController.h:
#import <UIKit/UIKit.h>
#class LVSBBSettingsViewController;
#pragma mark LVSBBSettingsViewController Delegate
#protocol LVSBBSettingsViewControllerDelegate <NSObject>
- (void)settingsViewControllerDidCancel:(LVSBBSettingsViewController *)controller;
- (void)settingsViewControllerDidSave:(LVSBBSettingsViewController *)controller;
#end
#pragma mark LVSBBSettingsViewController
#interface LVSBBSettingsViewController : UITableViewController
#property (nonatomic, weak) id <LVSBBSettingsViewControllerDelegate> delegate;
#property (weak, nonatomic) IBOutlet UISwitch *showBranchVarLabelsSwitch;
#property (weak, nonatomic) IBOutlet UISwitch *useAnimationSwitch;
#property (weak, nonatomic) IBOutlet UISwitch *showAllNodesSwitch;
#property (weak, nonatomic) IBOutlet UILabel *tempLabel;
- (IBAction)cancel:(id)sender;
- (IBAction)done:(id)sender;
#end
LVSBBSettingsViewController.m:
#import "LVSBBSettingsViewController.h"
#interface LVSBBSettingsViewController ()
#end
#implementation LVSBBSettingsViewController
// ... Xcode-generated stuff ...
- (IBAction)cancel:(id)sender
{
[self.delegate settingsViewControllerDidCancel:self];
}
- (IBAction)done:(id)sender
{
[self.delegate settingsViewControllerDidSave:self];
}
#end
LVSBBMainViewController.h:
#import <UIKit/UIKit.h>
#import "LVSBBSettingsViewController.h"
#interface LVSMainViewController : UIViewController <LVSBBSettingsViewControllerDelegate>
#end
LVSBBMainViewController.m:
#import "LVSMainViewController.h"
#import "LVSBBMasterViewController.h"
#interface LVSMainViewController ()
#end
#implementation LVSMainViewController
{
LVSBBMasterViewController *bbmvc;
}
// ...
- (void)viewDidLoad
{
[super viewDidLoad];
// Get main storyboard
UIStoryboard *st = [UIStoryboard storyboardWithName:[[NSBundle mainBundle].infoDictionary objectForKey:#"UIMainStoryboardFile"] bundle:[NSBundle mainBundle]];
// Instantiate bbmvc
bbmvc = [st instantiateViewControllerWithIdentifier:#"BBMasterViewControllerStoryboard"];
// Initialize settings
bbmvc.showBranchVarLabels = YES;
bbmvc.useAnimation = YES;
bbmvc.showAllNodes = NO;
}
...
#pragma mark LVSBBSettingsViewController Delegate
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"ShowSettings"])
{
// Get pointer to settings VC
UINavigationController *navigationController = segue.destinationViewController;
LVSBBSettingsViewController *settingsViewController = [navigationController viewControllers][0];
// Set delegate
settingsViewController.delegate = self;
// Populate settings VC
// (same problem occurs if I replace right-hand sides of next 3 lines with NO;)
settingsViewController.showBranchVarLabelsSwitch.on = bbmvc.showBranchVarLabels;
settingsViewController.useAnimationSwitch.on = bbmvc.useAnimation;
settingsViewController.showAllNodesSwitch.on = bbmvc.showAllNodes;
settingsViewController.tempLabel.text = #"HELLO";
}
}
- (void)settingsViewControllerDidCancel:(LVSBBSettingsViewController *)controller
{
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)settingsViewControllerDidSave:(LVSBBSettingsViewController *)controller
{
// Set settings in bbmvc
bbmvc.showBranchVarLabels = controller.showBranchVarLabelsSwitch.on;
bbmvc.useAnimation = controller.useAnimationSwitch.on;
bbmvc.showAllNodes = controller.showAllNodesSwitch.on;
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
UPDATE: As a workaround, I added properties in LVSBBSettingsViewController that match the properties in LVSMainViewController. In prepareForSegue:sender:, I set those properties instead of setting the controls directly. Then in viewDidLoad in LVSBBSettingsViewController, I set the control values based on the properties. This seems to work. Still not sure why I can't set the control values directly, though.
I have an NSMutableArray that I am trying to access from one of my ViewControllers to the other.
Here is what I am doing:
a.h:
#import "b.h"
.....
#property(nonatomic,strong) b *viewControllers;
a.m:
- (void)viewDidLoad
{
[super viewDidLoad];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
_viewControllers = [storyboard instantiateViewControllerWithIdentifier:#"createChallengeInfo"];
.....code....
}
....code....
-(IBAction)sendVideo:(id) sender
{
NSLog(#"%#",self.viewControllers.selectedCells);
}
Now when logging this I encounter an error, EXC_BAD_ACCESS (code=1,address =0x13765350).
Here is my other ViewController.
b.h:
...code....
#property (strong, nonatomic) NSMutableArray *selectedCells; <-- this is the array I want to access
...code...
b.m:
#import "a.h"
...import...
#interface b ()
#end
#implementation b
- (void)viewDidLoad
{
[super viewDidLoad];
/* INITIATE VARIABLE */
_selectedCells = [[NSMutableArray alloc] init];
....code....
}
...code...
So my issue is accessing, selectedCells. But firstly why am I getting a EXC_BAD_ACCESS? And secondly before I get the error It lays out the ViewController and shows the variable selectedCells as nil.
Suggestions, thoughts?
If "b" is embedded in a container view of "a", then it is already instantiated when "a" gets instantiated. Therefore, when you use instantiateViewControllerWithIdentifier:, you are creating a new instance, NOT the one you have on screen. Your viewDidLoad should look like this instead,
- (void)viewDidLoad
{
[super viewDidLoad];
_viewControllers = self.childViewControllers[0];
.....code....
}
Another way to get a reference to the embedded view controller is in prepareForSegue, which will be called right after your "a" controller is instantiated. Your "b" controller will be segue.destinationViewController.
I have been searching all morning how to do this. I have 2 View Controllers. From the root View Controller (ViewControllerA - which is a table view controller) you can go push to the second view controller (ViewControllerB).
In the ViewControllerB, there are two fields: contacts & textBody. When the user is done they can click on "Add". This will then go back to ViewControllerA. What I am trying to do now, is for every time that process occurs, all the information from ViewControllerB the user just added goes into a cell in ViewControllerA. The user can then add as many cells as they like.
What I can't do however, is get the information across the view controllers. I have been looking all morning at using the app delegate, singletons??, protocols, sharing properties, etc! But I am still stuck.
What I want to do, but can't, is for every time the user clicks "Add" on ViewControllerB, contacts & texts are put into an array. This array is then put into another array which holds all the smaller arrays which the user has created? If you have an ideas, or links to similar/sample code or tutorials, that would be much appreciated!
Try this using the delegate method as follows
Download Sample Project with XIBs
Download Sample Project With Storyboard
ParentViewController.h
#import <UIKit/UIKit.h>
#interface ParentViewController : UIViewController {
NSMutableArray *dataArray;
}
- (void)passData:(NSMutableArray *)array;
#end
ParentViewController.m
#import "ParentViewController.h"
#import "ChildViewController.h"
#implementation ParentViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Initialise the mutable array.
dataArray = [[NSMutableArray alloc] init];
}
- (IBAction)btnGoToSecondView:(id)sender {
ChildViewController *secondVC = [[ChildViewController alloc] initWithNibName:#"ChildViewController" bundle:nil];
secondVC.delegate = self;
[self presentViewController:secondVC animated:YES completion:nil];
}
- (void)passData:(NSMutableArray *)array {
[dataArray addObject:array];
NSLog(#"Data Passed = %#",dataArray);
}
#end
ChildViewController.h
#import <UIKit/UIKit.h>
#import "ParentViewController.h"
#class ParentViewController;
#interface ChildViewController : UIViewController {
NSMutableArray *tempArray;
}
#property (strong, nonatomic) IBOutlet UITextField *txtContact;
#property (strong, nonatomic) IBOutlet UITextField *txtTextBody;
#property(nonatomic, assign) ParentViewController *delegate;
#end
ChildViewController.m
#implementation ChildViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Initialise the mutable array.
tempArray = [[NSMutableArray alloc] init];
}
- (IBAction)btnPassDataBack:(id)sender {
if([self.delegate respondsToSelector:#selector(passData:)]) {
[tempArray addObject:_txtContact.text];
[tempArray addObject:_txtTextBody.text];
[self.delegate passData:tempArray];
}
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)viewDidUnload {
[self setTxtContact:nil];
[self setTxtTextBody:nil];
[super viewDidUnload];
}
#end
With Storyboard
If you are using storyboard then create a ParentViewController segue ChildViewController and give it a identifier in my sample it showChildView
Then use the following code to set the delegate
// Calling the segue to go to the child view and setting up the delegate.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showChildView"]) {
ChildViewController *childVC = segue.destinationViewController;
childVC.delegate = self;
}
}
Then to dismiss back to the ParentViewController use the following code (from my sample)
- (IBAction)btnPassDataBack:(id)sender {
if([self.delegate respondsToSelector:#selector(passData:)]) {
[tempArray addObject:_txtContact.text];
[tempArray addObject:_txtTextBody.text];
[self.delegate passData:tempArray];
}
[self.navigationController popToRootViewControllerAnimated:YES];
}
I would recommend using a singleton instance of your NSMutableDictionary as they have bailed me out of your exact situation multiple times (including custom frameworks and UITabBarControllers). Here is an example I'm currently using to implement a singleton. This methodology is also ARC-safe as well
mySingleton.h
#import <Foundation/Foundation.h>
#interface mySingleton : NSObject {
}
+ (NSMutableDictionary *) myMutableDict;
#end
mySingleton.m
#import "mySingleton.h"
#implementation mySingleton
+ (NSMutableDictionary *)myMutableDict
{
static NSMutableDictionary *singletonInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singletonInstance = [[NSMutableDictionary alloc]init];
});
return singletonInstance;
}
#end
As long as you include mySingleton.h in all of your view controllers you can access the data via [mySingleton myMutableDict]. For example: [[mySingleton myMutableDict] setObject:myObject forKey:myKey];
Good luck!
If the information is really "global" - it has only one instance across the whole app - then you should create a singleton as DB80Buckeye suggested.
If the information is something that truly belongs to ViewController1 and you want it to be modified in ViewController2 (ie ViewController2 is really part of ViewController1, it just happens to be on another screen), then you should pass that as part of the constructor of ViewController2.
-(void)view_controller_1_that_push_view_controller_2_onto_the_stack {
ViewController2* vc2 = [[ViewController2 alloc] initWithInformation:your_information];
[self.navigationController pushViewController:vc2 animated:YES];
}
#interface ViewController2
-(id)initWithInformation:(YourInformationClass*)info;
#end
Another way is to use notifications.
There are two ways to go here. The standard pattern for doing this is delegation. You don't need a singleton. ViewControllerA manages and lists your data. ViewControllerB doesn't need to know anything about all of that data so there's no reason to expose it via a singleton, etc.
Create a delegate protocol in ViewControllerB's header file. Something like this:
#protocol ViewControllerBDelegate
- (void)addContact:(NSString *)contact withBody:(NSString *)textBody;
#end
Now, specify that ViewControllerA will implement the delegate protocol in its header:
#interface ViewControllerA : UIViewController <ViewControllerBDelegate>
Don't forget to import ViewControllerB.h at the top of ViewControllerA's header.
In ViewControllerA's implementation, implement the delegate method you specified in the protocol:
- (void)addContact:(NSString *)contact withBody:(NSString *)textBody {
[self.someArray addObject:[[SomeObject alloc] initWithContact:contact body:textBody]];
[self.tableView reloadData];
}
That's obviously just an example -- not sure how you're managing your data structure and it's probably better to insert the cell someplace that makes sense.
Declare a delegate reference in ViewControllerB's header:
#property (weak, nonatomic) id<ViewControllerBDelegate> delegate;
When you present ViewControllerB, set ViewControllerA as the delegate.
ViewControllerB *b = [[ViewControllerB alloc] init...];
b.delegate = self;
In the selector triggered by the add button in ViewControllerB, call back on the delegate before popping the view controller off the navigation stack:
[self.delegate addContact:contact withBody:text];
where contact and text are the values the user entered.
One could also use a block instead of a delegate but the principle is the same -- have the second view controller only be responsible for taking input, in your case, and pass it back to the view controller managing the data.
Alternatively for delegate suggest using the following:
ViewControllerA.h:
#property (nonatomic, strong) ViewControllerB* viewControllerB;
In ViewControllerA.m
if (!self.viewControllerB)
{
self.viewControllerB = [[ViewControllerB alloc] initWithNibName: #"ViewControllerBr" bundle: nil];
}
[self.navigationController pushViewController: self.viewControllerB
animated: YES];
...
- (void) viewWillAppear: (BOOL) animated
if (self.viewControllerB)
{
NSString* contact = self.viewControllerB.contact;
NSLog(#"%#", contact);
}
...