I have a NSObject called GettingHere which has a NSString *content.
I then have a UIViewController on which I create a button programatically as follows (this button working as intended):
byAirButton = [UIButton buttonWithType:UIButtonTypeCustom];
byAirButton.tag = 1;
byAirButton.frame = CGRectMake(25, 140, 280.f, 40.f);
UIImage *airButton = [UIImage imageNamed:#"gettingHereByAirButton.png"];
[byAirButton setBackgroundImage:airButton forState:UIControlStateNormal];
[self.view addSubview:byAirButton];
[byAirButton addTarget:self action:#selector(byAirButtonClicked) forControlEvents:UIControlEventTouchUpInside];
For the action:#selector(byAirButtonClicked), I do the following. gettingHere is an instance of the GettingHere object.
- (void) byAirButtonClicked
{
gettingHere.content = #"This is how to get here by Air";
NSLog(#"Content: %#", gettingHere.content);
[self performSegueWithIdentifier:#"gettingHereSegue" sender:self];
}
The idea is to set the content for my GettingHere object and then just call that from the next view (GettingHereViewController) when the user clicks the byAirButton.
This NSLog shows that content is being set.
In my prepareForSegue, I do the following:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"gettingHereSegue"])
{
NSLog(#"Content to be passed: %#", gettingHere.content);
GettingHereViewController *vc = (GettingHereViewController *)segue.destinationViewController;
vc.gettingHere.content = gettingHere.content;
}
}
The segue works fine, but the NSLog shows my gettingHere object values as being (null).
Can anyone tell me where I am going wrong please? I have stepped through it several times but can't figure out where I am going wrong.
EDIT: Here is how I instantiate the GettingHere Object.
In the SubNavViewController.h
#import "GettingHereContent.h"
#interface SubNavViewController : UIViewController
#property GettingHereContent *gettingHere;
In the SubNavViewController.m
#import "SubNavViewController.h"
#import "GettingHereViewController.h"
#import "GettingHereContent.h"
#interface SubNavViewController ()
#end
#implementation SubNavViewController
#synthesize gettingHere;
And here is how I create the GettingHere Object:
GettingHere.h
#import <Foundation/Foundation.h>
#interface GettingHereContent : NSObject
#property (nonatomic, strong) NSString *content;
#end
GettingHere.m
#import "GettingHereContent.h"
#implementation GettingHereContent
#synthesize content;
#end
You never alloc init your gettingHere property. Try this in your init method of your VC
gettingHere = [[GettingHereContent alloc] init];
Also don't forget to release it: answer from here: alloc + init with synthesized property - does it cause retain count to increase by two?
#interface Foo : Bar {
SomeClass* bla;
}
#property (nonatomic, retain) SomeClass* bla;
#end
#implementation Foo
#synthesize bla;
-(id)init {
...
bla = [[SomeClass alloc] init];
...
}
-(void)dealloc {
[bla release];
...
[super dealloc];
}
Related
I'm trying to simply toggle a BOOL Attribute in my core data stack and also use that coredata bool to set the "state" of a UISwitch in viewDidLoad in my mainView.
following scenario:
Switch is off, user hits edit(save) UIButton, --> that toggles the settingSysTimeOverride Attribute of entity Setting from #NO to #YES
next time app launches, in viewDidLoad, I fetch the core data stack and look at status of settingSysTimeOverride and use that to
set the "state" of my UISwitch.
But for some reason, my value does NOT get stored to core data stack.
The whole project is attached, also here is my code.
MainViewController.m
#import "MainViewController.h"
#import "AppDelegate.h"
#interface MainViewController ()
#property (nonatomic, strong)NSManagedObjectContext *managedObjectContext;
#property (nonatomic, strong)NSFetchedResultsController *fetchedResultsController;
#property (strong, nonatomic) NSMutableArray *settingsArray;
#end
#implementation MainViewController
#synthesize editSetting;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (NSManagedObjectContext *)managedObjectContext
{
return [(AppDelegate*)[[UIApplication sharedApplication]delegate]managedObjectContext];
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Setting" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"settingSysTimeOverride == %#", editSetting];
[fetchRequest setPredicate:predicate];
NSError *error;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
NSLog(#"ERROR! %# - %#", [error localizedDescription], [error userInfo]);
} else {
NSLog(#"FETCH SUCCESSFUL");
}
if ((fetchedObjects.count) >0) {
// list array contents
for (int i=0; i < (fetchedObjects.count); i++) {
// output for debug purpose
NSLog(#"Array-index [%i]: %#", i, fetchedObjects[i]);
}
}
// check settingSysTimeOverride and set UISwitch-State
if (editSetting.settingSysTimeOverride.boolValue == 0) {
// turn switch to OFF - Position
_overrideSysTimeSwitch.on = NO;
} else {
// turn switch to ON - Position
_overrideSysTimeSwitch.on = YES;
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)editSave:(UIBarButtonItem *)sender
{
// toggle BOOL status of settingSysTimeOverride here
//
}
- (IBAction)overrideSysTime:(UISwitch *)sender
{
}
- (IBAction)timeFormat:(UISwitch *)sender {
}
#end
MainViewController.h
#import <UIKit/UIKit.h>
#import "Setting.h"
#interface MainViewController : UIViewController <NSFetchedResultsControllerDelegate>
#property (nonatomic, strong)Setting *editSetting;
#property (strong, nonatomic) IBOutlet UIBarButtonItem *editSaveButton
#property (strong, nonatomic) IBOutlet UILabel *overrideSysTimeLabel;
#property (strong, nonatomic) IBOutlet UILabel *timeFormatLabel;
#property (strong, nonatomic) IBOutlet UISwitch *overrideSysTimeSwitch;
#property (strong, nonatomic) IBOutlet UISwitch *timeFormatSwitch;
- (IBAction)editSave:(UIBarButtonItem *)sender;
- (IBAction)overrideSysTime:(UISwitch *)sender;
- (IBAction)timeFormat:(UISwitch *)sender;
#end
AppDelegate.h
#import <UIKit/UIKit.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
#end
Setting.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface Setting : NSManagedObject
#property (nonatomic, retain) NSString * settingName;
#property (nonatomic, retain) NSNumber * settingSysTimeOverride;
#property (nonatomic, retain) NSNumber * settingTimeFormat;
#end
Setting.m
#import "Setting.h"
#implementation Setting
#dynamic settingName;
#dynamic settingSysTimeOverride;
#dynamic settingTimeFormat;
#end
Can someone please help me with this???
here is what I was doing wrong, I hope it's going to help others in the future to avoid running in the same issues:
I forgot to point my NSManagedObject at the beginning of my fetched array.
NSManagedObject *matches;
matches=[objects objectAtIndex:(0)];
The code in one piece would look like this:
NSManagedObjectContext *context;
NSEntityDescription *entityDesc;
NSFetchRequest *request;
NSPredicate *pred;
NSManagedObject *matches;
NSArray *objects;
NSUInteger elementsInArray;
context = [self managedObjectContext];
entityDesc = [NSEntityDescription entityForName:#"Setting" inManagedObjectContext:context];
pred = [NSPredicate predicateWithFormat:#"(settingName = %#)", #"User-Settings"];
request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];
[request setPredicate:pred];
matches = nil;
NSError *errorFS = nil;
if (!(objects = [context executeFetchRequest:request error:&errorFS])) {
// fetch failed
NSLog(#"Fetch failed: %# - %#", [errorFS localizedDescription], [errorFS userInfo]);
} else {
// fetch succeeded
NSLog(#"Fetch Succeeded");
}
if ([objects count] == 0)
{ // does not exist -> error?
} else
{
matches=[objects objectAtIndex:(0)]; // <- HERE WAS THE ERROR !!!!!
// # system time override switch
if([[matches valueForKey:#"settingSysTimeOverride"] boolValue]) {
_sysTimeOverrideSwitch.on = YES;
} else {
_sysTimeOverrideSwitch.on = NO;
}
}
I'm not sure what I'm doing wrong. I'm thinking its because the NSMutableArray's *name and *field are declared in a different file.
#import <Foundation/Foundation.h>
#interface xmlToUrl : NSObject {
NSString *base_url;
NSMutableArray *field;
NSMutableArray *name;
}
#property(nonatomic,retain)NSString *base_url;
#property(nonatomic, retain)NSMutableArray *field;
#property(nonatomic, retain)NSMutableArray *name;
#end
and
#import "xmlToUrl.h"
#implementation xmlToUrl
#synthesize base_url;
#synthesize field;
#synthesize name;
-(id) init
{
self = [super init];
if (self) {
field = [[NSMutableArray alloc] init];
name = [[NSMutableArray alloc] init];
}
return self;
}
-(void)dealloc
{
[base_url release];
[field release];
[name release];
[super dealloc];
}
#end
The NSMutableArrays are filled in the ViewController class:
//nodeContent is just a NSMutableString being added to the *name and *field NSMutableArrays
if([ending isEqualToString:#"name"]){
if(![nodeContent isEqualToString:#""])
{[xmlToUrlObject.name addObject:nodeContent];}
}
else if([ending isEqualToString:#"field"]){
if(![nodeContent isEqualToString:#""])
{[xmlToUrlObject.field addObject:nodeContent];}
Error = Expected '.' before '.' token. (on the first line of the code below)
What I want for output: *url string contains base_url, urlPart2, and urlPart3 all joined in order.
ex:
base_url = #"www."
urlPart2 = #"mywebsite"
urlPart3 = #".com"
url = #"www.mywebsite.com"
//xmlToUrl is an instance of its own class (.m file) It contains the *name and *field NSMutableArray
//xmlToUrl.h is inherited in this file
NSMutableString *urlPart2 = [xmlToUrl.name objectAtIndex: 0];
[xmlToUrl.name removeObjectAtIndex:0];
NSMutableString *url = [xmlToUrl.base_url stringByAppendingString:urlPart2];
if([xmlToUrl.field count] != 0)
{NSMutableString *urlPart3 = [xmlToUrl.field objectAtIndex: 0];
[xmlToUrl.field removeObjectAtIndex:0}
url = [url stringByAppendingString:urlPart3];
[urlPart2 release];
[urlPart3 release];
You are trying to access a property on a class, and not on the instance:
#interface xmlToUrl : NSObject {
and
NSMutableString *urlPart2 = [xmlToUrl.name objectAtIndex: 0];
You can only access the property on an instance of xmlToUrl, just like you do in the following line of code:
{[xmlToUrlObject.name addObject:nodeContent];}
Here, xmlToUrlObject is an instance, and not the class.
Okay, so I'm pretty new to xcode but I cannot find something specific to this issue anywhere. So I declare the array and instantiate it in the following files:
//xmlToUrl.h
#import <Foundation/Foundation.h>
#interface xmlToUrl : NSObject {
NSMutableArray *field;
NSMutableArray *name;
}
#property(nonatomic, retain)NSMutableArray *field;
#property(nonatomic, retain)NSMutableArray *name;
#end
and
//xmlToUrl.m
#import "xmlToUrl.h"
#implementation xmlToUrl
#synthesize field;
#synthesize name;
-(void)dealloc
{
[field release];
[name release];
[super dealloc];
}
#end
So this is where I am confused. I don't know how to correctly "alloc" or "init" the mutable arrays, nor how to handle the add/remove operations from another file which inherits xmlToUrl.h.
The code (in the other file) as I have it now just prints null. Its listed below. What am I doing wrong?!?
//nodeContent is just a NSMutableString
[xmlToUrlObject.name addObject:nodeContent];
NSLog(#"xml Name = %#", xmlToUrlObject.name);
//I omitted all the operational code here but if I NSLog nodeContent it prints the correct values
[xmlToUrlObject.field addObject:nodeContent];
NSLog(#"xml Field = %#", xmlToUrlObject.field);
You need an init function in your implementation file, it would look similar to the following
-(id) init
{
self = [super init];
if (self) {
field = [[NSMutableArray alloc] init];
name = [[NSMutableArray alloc] init];
}
return self;
}
Then whenever you create an instance of your xmlToUrl class via [[xmlToUrl alloc] init] you will have an instance of your class that has already initialized your two NSMutableArrays
I 'm new to IOS and Objective C.
The scenario is I have 2 buttons, which open (with segue) 2 view controllers containing a UIWebview.
I thought is better to do it with 1 UIWebView so I tried to pass the request object of the webvew and use only one webview controller.
so I got the wwwBtn (UIButton that opens a site) and fbBtn (UIButton that goes to a Facebook URL) my viewController and the wwwWebViewController which contains th UIWebView.
Here is how I did it.
The viewController.h file :
#interface ViewController : UIViewController {
UIButton *wwwBtn;
UIButton *fbButton;
}
#property (retain, nonatomic) IBOutlet UIButton *wwwBtn;
#property (retain, nonatomic) IBOutlet UIButton *fbBtn;
The ViewController.m file :
#import "ViewController.h"
#import "wwwWebViewController.h"
#implementation ViewController
#synthesize wwwBtn;
#synthesize fbBtn;
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"web"]) {
NSString *urlstr=#"http ://www.google.com";
wwwWebViewController *vc = [segue destinationViewController];
vc.urlStr = urlstr;
} else if ([[segue identifier] isEqualToString:#"fb"]) {
NSString *urlstr = #"http://www.facebook.com";
wwwWebViewController *vc = [segue destinationViewController];
vc.urlStr = urlstr;
}
}
the wwwWebViewController.h file :
#interface wwwWebViewController : UIViewController {
UIWebView *webView;
}
#property (retain, nonatomic) IBOutlet UIWebView *webView;
The wwwWebViewController.m file :
- (void)viewDidLoad
{
NSURL *url = [NSURL URLWithString:urlStr];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
[webView loadRequest:requestObj];
[super viewDidLoad];
}
Do as the following, you will assign this class to the destination UIViewControllers that you will need to pass the NSString *urlstr to them:
WebViewController.h
#interface WebViewController : UIViewController {
NSString *urlstr;
}
#property (strong, nonatomic) IBOutlet UIWebView *WebView;
#property (strong, nonatomic) NSString *urlstr;
WebViewController.m
#implementation WebViewController
#synthesize WebView;
#synthesize urlstr;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSURL *url = [NSURL URLWithString:urlstr];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
[self.WebView loadRequest:requestObj];
}
Now it's time to create two segues from my main storyboard class InfoViewController to the destination class WebViewController, in my case I've created three segues but only two are using the WebViewController class.
You've also to give the segues a spacial Identifier for each to target them programmatically in the main class InfoViewController.
let's check out how the InfoViewController : UITableViewController will look like:
InfoViewController.m
#import "InfoViewController.h"
#import "WebViewController.h"
#interface InfoViewController ()
#end
#implementation InfoViewController
#synthesize AboutCell = _AboutCell;
#synthesize CGCell = _CGCell;
#synthesize FTACell = _FTACell;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *AboutCellClicked = [self.tableView cellForRowAtIndexPath:indexPath];
UITableViewCell *CGCellClicked = [self.tableView cellForRowAtIndexPath:indexPath];
UITableViewCell *FTACellClicked = [self.tableView cellForRowAtIndexPath:indexPath];
if (AboutCellClicked == _AboutCell) {
[self performSegueWithIdentifier:#"AboutPush" sender:self];
} else if (CGCellClicked == _CGCell) {
[self performSegueWithIdentifier:#"CGPush" sender:self];
} else if (FTACellClicked == _FTACell) {
[self performSegueWithIdentifier:#"FTAPush" sender:self];
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
WebViewController *webController = [[WebViewController alloc] init];
if ([[segue identifier] isEqualToString:#"CGPush"]) {
NSString *urlstr=#"http://www.google.com";
webController = [segue destinationViewController];
webController.urlstr = urlstr;
} else if ([[segue identifier] isEqualToString:#"FTAPush"]) {
NSString *urlstr=#"http://www.yahoo.com";
webController = [segue destinationViewController];
webController.urlstr = urlstr;
}
}
#end
I hope this will solve your problem, If you have any question do not hesitate to ask.
The navigationbar is failing to appear, works fine in a UITableView, but fails inside a popoverController
Initiate a popover popoverController in UIViewController
-(IBAction) btnShowMovies:(id) sender {
if (self.popoverController == nil) {
teamAController *movies =
[[teamAController alloc]
initWithNibName:#"teamAController"
bundle:[NSBundle mainBundle]];
UIPopoverController *popover =
[[UIPopoverController alloc] initWithContentViewController:movies];
popover.delegate = self;
[movies release];
self.popoverController = popover;
[popover release];
}
CGRect popoverRect = [self.view convertRect:[btn frame]
fromView:[btn superview]];
popoverRect.size.width = MIN(popoverRect.size.width, 100);
[self.popoverController
presentPopoverFromRect:popoverRect
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionDown
animated:YES];
}
teamAController.h
#interface teamAController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
UITableView *tableView;
NSArray *theArray;
}
#property (nonatomic, retain) NSArray *theArray;
#property (nonatomic, retain) IBOutlet UITableView *tableView;
-(void) createArray;
teamAController.m
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title= #"FooBarExtreme";
self.contentSizeForViewInPopover = CGSizeMake(250.0, 300.0);
[self createArray];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
Everything works, I have lovely table with images etc, correct sized and placed popover just no title bar..... ?
I found the solution/problem by following the tutorial at http://mobiforge.com/designing/story/using-popoverview-ipad-app-development.
Worth noting that I found this the most comprehensive one on creating uiPopoverController with uiNavigationBar elements from UIButtons.
The issue is that the popover itself belongs to the view that calls it. The content is derived from the xlib/view you load into it. But not the titlebar. You call that in the parent view view.
This code is in the main view and is called from the UIButton
// BookMarksViewController is the class that contains the code/xib for the popover's content
// Of overarching importance is creating it as a UITableViewController
if (self.popoverController == nil) {
BookMarksViewController *bookMarksViewController =
[[BookMarksViewController alloc]
initWithNibName:#"BookMarksViewController"
bundle:[NSBundle mainBundle]];
// Here's the rub: because in effect this view is controlling the popover
// we have to assign nav bar stuff here. Sigh.
bookMarksViewController.navigationItem.title = #"Territories";
UINavigationController *navController =
[[UINavigationController alloc]
initWithRootViewController:bookMarksViewController];
bookMarksViewController.contentSizeForViewInPopover = CGSizeMake(320, 400);
UIPopoverController *popover =
[[UIPopoverController alloc]
initWithContentViewController:navController];
popover.delegate = self;
[bookMarksViewController release];
[navController release];
self.popoverController = popover;
[popover release];
}
CGRect sourceRect = [self.view convertRect:[btn frame] fromView:[btn superview]];
[self.popoverController presentPopoverFromRect:sourceRect
inView:self.view permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES];