When are interface builder IBOutlet objects created - objective-c

I am using the iPad master / detail project template and I'm trying to update some UILabels in the detailViewController when the app is first run.
Here is My Code :
(void)setObject:(id)newObject
{
if (_object != newObject) {
[_object release];
_object = [newObject retain];
[self configureView];
}
if (self.masterPopoverController != nil) {
[self.masterPopoverController dismissPopoverAnimated:YES];
}
}
- (void)configureView
{
[self updateDetails];
}
- (void) updateDetails
{
NSLog(#"Details = %#", self.details);
NSLog (#"detailLabel %#", self.detailLabel);
self.detailLabel.text = [self.details objectForKey:#"aKey"];
}
- (IBAction)refresh:(UIBarButtonItem *)sender {
[self updateDetails];
}
setEvent is called from the Master View Controller's viewDidLoad method as selecting it's tableview's 1st row as a default.
if (![self.tableView indexPathForSelectedRow])
{
[self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] animated:NO scrollPosition:0];
[self.detailViewController setObject:[self.sortedObjects objectAtIndex:0]];
}
When I run the code the detailLabel is not changed and the NSLog says self.detailLabel is (null). If 'refresh' is called later from a button click detailLabel is not null and updates correctly. How can I do this to make sure the detailLabel has been created and is not (null)?

The IBOutlet objects will be created at the time of viewDidLoad() of that object(detail view, but not master view).
call the [self updateDetails]; in viewdidLoad() method of detail view controller to avoid this problem.

Related

Unable to Get View Class in the top

I am trying to get current view open in my code using this code in delegate while handling Push Notification
NSArray *views = window.subviews;
NSLog(#"views: %#", views);
UIView *topview=[views lastObject];
when is click on topview and see using below tool (eye mark) it shows the current view
open .
But when i am try to get its kind of class using below two method none of these work
for(UIView *view in window.subviews)
{
if([view isKindOfClass:[MyClass class]])
{
NSLog(#"view is a MyClass\n");
}
}
or
if ([topview isKindOfClass:[MyClass class]])
{
NSLog(#"topview is a MyClass\n");
}
else
{
NSLog(#"topview is NOT a MyClass\n");
}
How can i get my visible view name of kind of class.
self.navigationController.viewControllers returns a UIViewController* array, not a UIView* array.
So, for your first solution:
for(UIViewController *viewController in self.navigationController.viewControllers)
{
if([viewController.view isKindOfClass:[MyClass class]])
{
NSLog(#"view is a MyClass\n");
}
}
will work.
For the visible UIViewController*, you can use:
UIViewController* viewController = self.navigationController.visibleViewController;
For the topmost view:
UIView* topmostView = [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];

NSUserDefaults not appearing first appearence

So I've been learning iOS for the past couple months and have recently ran into this problem. I have a settings screen inside my app after a log in process that should save some basic information pertaining to the user. The issue is when the view first appears from a tab bar controller, the static grouped table view is blank with none of the information available for the cell.detailLabel.text. I used NSLog to discover that at first when retrieving the objects from keys, they are null. However, when I select a cell to change it's information and push on another view controller, I can then go back and all the values will appear from previous inputs saved to NSUser defaults. I was curious why this happens and for a solution. Thanks
#import "SettingsController.h"
#import <Parse/Parse.h>
#import "LogInViewController.h"
#import "AddSettings.h"
#import "AddUrination.h"
#import "ChooseAlarmController.h"
#interface SettingsController ()
#end
#implementation SettingsController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
UIBarButtonItem *addUrination=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(addUrinationView:)];
self.navigationItem.rightBarButtonItem=addUrination;
/*Rename the back button which every pushed on controller will have*/
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:#"Cancel" style:UIBarButtonItemStyleBordered target:nil action:nil];
self.navigationItem.backBarButtonItem = backButton;
NSLog(#"view loaded");
}
-(void)viewWillAppear:(BOOL)animated
{
/*Everytime view appears, we want to repopulate the table with updated content*/
NSLog(#"Settings View appeared,Load the keys");
/*Load every cell with appropiate details*/
NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
NSIndexPath *path=[NSIndexPath indexPathForRow:0 inSection:0];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:path];
cell.detailTextLabel.text=[defaults objectForKey:#"FirstNameKey"];
NSLog(#"%#",cell.detailTextLabel.text);
path=[NSIndexPath indexPathForRow:1 inSection:0];
cell=[self.tableView cellForRowAtIndexPath:path];
cell.detailTextLabel.text=[defaults objectForKey:#"LastNameKey"];
path=[NSIndexPath indexPathForRow:2 inSection:1];
cell=[self.tableView cellForRowAtIndexPath:path];
cell.detailTextLabel.text=[defaults objectForKey:#"NumberOfUrinationsKey"];
[self.tableView deselectRowAtIndexPath:self.tableView.indexPathForSelectedRow animated:YES];
path=[NSIndexPath indexPathForRow:0 inSection:1];
cell=[self.tableView cellForRowAtIndexPath:path];
cell.detailTextLabel.text=[defaults objectForKey:#"StartingAlarmKey"];
path=[NSIndexPath indexPathForRow:1 inSection:1];
cell=[self.tableView cellForRowAtIndexPath:path];
cell.detailTextLabel.text=[defaults objectForKey:#"FinalAlarmKey"];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(IBAction)addUrinationView:(id)sender
{
[self performSegueWithIdentifier:#"AddUrinationSegue" sender:self];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// If Log Out Button is selected
if(indexPath.row==0 && indexPath.section==2){
NSLog(#"Log Out selected");
[PFUser logOut];
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"Are You Sure?" message:#"If you would like to change your mind, press cancel. Otherwise choose log out" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Log Out", nil];
[alert show];
}
NSLog(#"Selected row is %ld %ld", (long)indexPath.section,(long)indexPath.row);
/*Segue depends on which cell is selected. First section segues to text input (AddSettings.h)*/
if((indexPath.section==0 && indexPath.row<2) || (indexPath.section==1 && indexPath.row==2)){
[self performSegueWithIdentifier:#"AddSettingSegue" sender:self];
}
/*Choose alarm controller is selected*/
if(indexPath.section==1 && indexPath.row<2){
[self performSegueWithIdentifier:#"AddAlarmSegue" sender:self];
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
if([segue.identifier isEqualToString:#"AddSettingSegue"]){
AddSettings *settingsController=[segue destinationViewController];
/*index path contains both the section and row of the selected cell*/
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSLog(#"Section:%ld Row:%ld",(long)indexPath.section,(long)indexPath.row);
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
settingsController.titleOfController=cell.textLabel.text;
}
if([segue.identifier isEqualToString:#"AddUrinationSegue"])
{
AddUrination *addUrinationView=[segue destinationViewController];
}
if([segue.identifier isEqualToString:#"AddAlarmSegue"]){
ChooseAlarmController *alarm=[segue destinationViewController];
NSIndexPath *indexPath=[self.tableView indexPathForSelectedRow];
UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:indexPath];
alarm.titleOfController=cell.textLabel.text;
}
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(buttonIndex==1){
[self performSegueWithIdentifier:#"UnwindToLogIn" sender:self];
}
}
#end
Add [super viewWillAppear:animated] to the top of your viewWillAppear: override. According to Apple's documentation for viewWillAppear:,
"If you override this method, you must call super at some point in your implementation."
While your application generally won't crash or anything if you omit it, important initialization performed by the base class will not occur unless you call [super viewWillAppear:animated], which may result in unexpected behaviour, such as label values not appearing in your table view cells.
As a best practice, you should always call the super method whenever you override one of Apple's methods, unless you explicitly do not want the default behaviour to occur (eg. overriding touchesBegan:withEvent:). Though there are exceptions, generally overridden initialization methods like viewDidLoad and viewWillAppear: should call their super method at the beginning of the method, while overridden teardown methods like viewWillDisappear: should call their super method at the end.

UITableView is null after first data load, reloadData does not work

I have a custom UIView with a UITableView in it. I connect the delegate and dataSource via interface builder, it looks like this: http://postimg.org/image/nj9elaj4h/ (may not upload images yet :( )
When I load the view, the data is displayed as it should be. But when I try to call reloadData, nothing happens. I checked if the uitableview is set, but it is NULL. But as soon as I drag the tableView and it reloads it views, the new data is presented. Anyone got an idea why reloadData does not work?
.h looks like this:
#interface NextTitleView : UIView<UITableViewDataSource,UITableViewDelegate,SociusClientDelegate,UIActionSheetDelegate,Ne xtTitleCustomCellDelegate>
{
NexTitleCustomCell* _cellInFocus;
}
#property(nonatomic,retain)IBOutlet UITableView* _tableViewNextTitle;
#end
thanks for your help :D
EDIT: Added .m file
#implementation NextTitleView
#synthesize _tableViewNextTitle;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
-(id)init
{
if(self)
{
[SharedSingeltons sharedInstance]._client.delegateCustomClient = self;
_tableViewNextTitle = [[UITableView alloc]init];
}
return self;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 2;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if(section == 0)
return #"Now playing";
if(section == 1)
return #"Comming Next";
else
return #"";
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(section == 0)
return 1;
if (section == 1)
return [[SharedSingeltons sharedInstance]._client._musicList count];
else
return 0;
}
-(NexTitleCustomCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NexTitleCustomCell* cell = [[NexTitleCustomCell alloc]init];
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"NextTitleCustomCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
MusicItem* item = [[SharedSingeltons sharedInstance]._client._musicList
objectAtIndex:indexPath.row];
cell.delegate = self;
cell._labelSongTitle.text = item._songTitle;
cell._labelSongTitle.textColor = [UIColor blackColor];
cell._labelSubtitle.text = item._artist;
cell._identifier = item._songIdentifier;
cell._labelRating.text = item._rating.stringValue;
return cell;
}
-(void)clientDidReceiveMusicList:(SociusClient *)sender list:(NSMutableArray *)array
{
for(MusicItem* item in [SharedSingeltons sharedInstance]._client._musicList)
{
NSLog(#"rating:%#",item._rating);
}
NSLog(#"TAbleVIEW:%#",_tableViewNextTitle);
[self._tableViewNextTitle reloadData];
}
-(void)didPressActionButton:(NexTitleCustomCell *)sender
{
NSLog(#"Show alert view");
_cellInFocus = sender;
UIActionSheet *popupQuery = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:#"Vote Up", #"Like",#"Remember", nil];
[popupQuery showInView:self];
}
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(buttonIndex == 0)
{
NSLog(#"Vote up");
[self sendUpdateVoteForSong];
}
}
-(void)sendUpdateVoteForSong
{
NSMutableDictionary* dict = [[NSMutableDictionary alloc]init];
[dict setObject:_cellInFocus._identifier forKey:#"Vote"];
NSLog(#"Identifier:%#",_cellInFocus._identifier);
[[SharedSingeltons sharedInstance]._client sendObject:dict error:nil];
}
#end
I would say you are calling reload data too soon, probably in initWithNibName, you should be calling it in viewDidLoad.
I just set up a uiviewcontroller to handle the view. Now it works fine.
I think that UIActionSheet led to the problem,you can try to reloadData twice.
I noticed you are New-ing your Table view, but it's an Outlet... You don't need to alloc init your table view, if it's an IBOutlet. So either get rid of the IBOutlet, and just declare it as a property (but then you need to make sure you lay out your Table view programmatically), or keep the IBOutlet, and get rid of the code to alloc init it. Currently also your datasource and delegate are set from IB, so if you alloc init your table view, those won't be set anymore...
The tableview outlet should NOT be nil.
Can you put a breakpoint in awakeFromNib, and see if the TableView outlet is NIL there?
Are you loading the View Class that contains the table view by using its NIB file properly?
If you just embed the View class in the storyboard, it will not load the NIB automatically. I usually use a View container in that case, then load the NIB programmatically, and embed the loaded view in the view container programmatically.
NSArray *arrayXibObjects = [[NSBundle bundleWithIdentifier:#"net.mycompany.myappid"] loadNibNamed:#"myNibName" owner:nil options:nil];
for (id object in arrayXibObjects) {
if ([object isKindOfClass:myNibsClass]) {
return object; // this is your class loaded from NIB
}
}
This code can be placed in a utility method, to make it accessible with 1 line of code.
The returned Class is going to have the IBOutlets connected from the NIB to it's respective Class.
Now check in the debugger:
po [loadedClassFromNib tableView] // should not be NIL
Then embed the loaded NIB in the container like this: (or use constraints)
[self.viewContainer addSubview: classLoadedFromNib];
classLoadedFromNib.frame = self.viewContainer.frame;

How to use UIPopOver to input text in to UITextField?

I would like to learn how would I make a UITextField get text from a UIPopover view. Let's say I have buttons with numbers on my popover and I want these numbers to be input into the textfield.
Some people sugested to us BOOL like this:
- (BOOL)textFieldShouldBeginEditing:(UITextField *) textField {
[self.myPopover presentPopoverFromRect:textField.frame
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
return NO;
}
And one more:
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView {
if(popoverController == nil){ //make sure popover isn't displayed more than once in the view
popoverController = [[UIPopoverController alloc] initWithContentViewController:popoverDetailContent];
}
[popoverController presentPopoverFromRect:textView.frame
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
popoverController.delegate = self;
return NO; // tells the textfield not to start its own editing process (ie show the keyboard)
}
Both are not making much change, my textField still calls the default iPad keyboard instead of my popover.
Second example uses delegate popoverController and my controller is flipsidePopoverController.
Could I use an IBAction like this?
- (IBAction)togglePopover:(id)sender {
if (self.flipsidePopoverController) {
[self.flipsidePopoverController dismissPopoverAnimated:YES];
self.flipsidePopoverController = nil;
} else {
[self performSegueWithIdentifier:#"showAlternate" sender:sender];
}
}

Receiving Drag events on an NSWindow when the window contains a single WebView view

I am new to objective-c and cocoa so please break things down for me. I'm working on a project started by another developer and have only been working in objective-c for 3 days.
I have an NSWindow subclass that contains a WebView view. The WebView content that is loaded is a Silverlight plugin. I registered the NSWindow to receive Drag events. The drag events are being generated but only when the drag occurs within the NSWindow Title Bar. I register for the drag events in the load method.
AdminWindow.mm
#import "AdminWindow.h"
#import "NativeMessageReceiver.h"
extern AdminWindow* adminRiaWindow;
#implementation AdminWindow
#synthesize adminWebView;
BOOL isAdminContentLoaded;
-(void) load
{
if (!isAdminContentLoaded)
{
NSLog(#"loading Admin window");
NSString *curDir = [[NSBundle mainBundle] bundlePath];
NSString* url = [NSString stringWithFormat: #"file://%#/Contents/Resources/RIA/AdminContentMac.html",curDir];
[[adminWebView mainFrame] loadRequest: [NSURLRequest requestWithURL: [NSURL URLWithString: url]]];
[adminWebView setDrawsBackground:NO];
id win = [adminWebView windowScriptObject];
NativeMessageReceiver* receiver = [NativeMessageReceiver getInstance];
[win setValue:receiver forKey:#"NativeMessageReceiver"];
receiver.adminWebView = adminWebView;
isAdminContentLoaded = YES;
}
}
-(void) show
{
[self load];
[self setIsVisible: YES];
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
[self makeKeyAndOrderFront: self];
[self makeMainWindow];
[self center];
}
-(void) hide
{
[self setIsVisible: NO];
}
- ( BOOL ) windowShouldClose : ( id ) sender
{
[self setIsVisible: NO];
return NO;
}
- (BOOL) canBecomeKeyWindow
{
return YES;
}
- (BOOL) canBecomeMainWindow
{
return YES;
}
#end
extern "C" void ShowAdminWindow()
{
NSLog(#"showing Admin window");
if (![NSThread isMainThread])
[adminRiaWindow performSelectorOnMainThread:#selector(show) withObject:nil waitUntilDone:YES];
else
{
[adminRiaWindow show];
}
}
extern "C" void HideAdminWindow()
{
if (![NSThread isMainThread])
{
[adminRiaWindow performSelectorOnMainThread:#selector(hide) withObject:nil waitUntilDone:YES];
}
else
{
[adminRiaWindow hide];
}
}
CustomeWebView
#implementation SteamPunkWebView
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
[self registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
NSLog(#"In Custom View Init");
}
return self;
}
I think you're only getting drag events in the title bar because you registered the window to receive the events, not the web view.
Try this instead:
[self.adminWebView registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
WebViews are one of the most complex views in Cocoa and are a special case when it comes to dragging. Instead of implementing the standard NSView dragging behaviour, you need instead to set an object as the web view's WebUIDelegate and implement the following delegate method:
‑webView:dragDestinationActionMaskForDraggingInfo:
You can then control how you want the web view to respond to the drag action. The WebUIDelegate protocol has several other methods to control dragging, so you should read the documentation for more detail.
To actually receive the dragged objects and process them, you will need to subclass WebView and implement ‑draggingEnded:.
You definitely do not need to add any dragging methods to the window itself.