I'm new to the NSXMLParser, so I decided to take this tutorial: http://www.xcode-tutorials.com/parsing-xml-files/ and it was great. But in my app I used parser not in AppDelegate, but in other ViewController. I changed initialization to this:
-(XMLParser *)initXMLParser {
[super init];
viewController = (ViewController *)[[UIApplication sharedApplication] delegate];
return self;
}
The parser itself works well but it doesn't add any objects to the array in view controller in which the objects should be added. Can anyone help?
Your code call still your app delegate
Try with this kind of code
#interface XMLParser : NSObject {
NSMutableString *currentElementValue;
id<NSXMLPArserDelegate> delegate;
Book *aBook;
}
-(XMLParser *)initXMLParserWithDelegate:(id<NSXMLPArserDelegate>) delegate;
#end;
-(XMLParser *)initXMLParserWithDelegate:(id<NSXMLPArserDelegate>) _delegate {
self = [super init];
if(self) {
delegate = _delegate;
}
return self;
}
And set the delegate with self in your constructor
Related
I have a TableViewController that segues into a TabBarViewController.
I know how to pass my object via a segue, but not by a relationship like the TabBarViewController and it's tab share.
How can I do this? From the TabView is there a way to access the TabBarViewControllers member variables?
Update:
This is how I've solved the problem so far, but I'm not crazy about using the AppDelegate to do this...
Add the Following to WhateverYouNamedYourAppDelegate.h
#class myObjectIWantToPass;
#property (strong, nonatomic) myObjectIWantToPass *object;
Then add the following to the View Class file you have your data in that you want to pass on. I'm going to assume you know how to set up your object already in this file if your planning on passing it to another view.
WhateverYouNamedYourAppDelegate *appDelegate =
(WhateverYouNamedYourAppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.object = object;
Then you do some similar work to retrieve the object back from the appDelegate in your destination View Class.
WhateverYouNamedYourAppDelegate *appDelegate = (WhateverYouNamedYourAppDelegate *)[[UIApplication sharedApplication] delegate];
object = appDelegate.object;
You can make singleton classes, so that all of the controllers can access those variables in the Singleton. See Code below
SingletonClass.h
#interface SingletonClass : NSObject {
NSString *someString;
}
#property(nonatomic, retain)NSString *someString;
+(id)shared;
#end
SingletonClass.m
#import "SingletonClass.h"
static SingletonClass *aShared;
#implementation LibShared
#synthesize someString;
+(id)shared
{
if (aShared == nil) {
aShared = [[self alloc] init];
}
return aShared;
}
-(id)init
{
if (self = [super init]) {
}
}
-(void)dealloc
{
[someString releease];
[super dealloc];
}
In the tabbar you can set the variable on SingletonClass:
[[SingletonClass shared] setSomeString:#"Value_Set"];
On the tableViewController, you can get the property of the someString variable on the SingletonClass:
NSString *string = [[SingletonClass shared] someString];
There's no need for a singleton pattern here. Instead, you can send the data-object forwards in - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender just as you do normally, you just need to find the correct viewController in the UITabBarController's viewControllers property.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"MyTabBarSegue]) {
UITabBarController *tabBarController = segue.destinationViewController;
// Either set the index here, if you know for sure which viewController is which, or
// Enumerate the viewControllers for isKindOfClass:[MYCustomViewController class] to be robust and change-proof
MYCustomViewController *myVC = [[tabBarController viewControllers] objectAtIndex:0];
myVC.dataObject = self.dataObject;
}
}
this is probably simple but I'm stuck!
Basically I have a parent and child view controller, and I'm trying to pass data from the child to the parent.
//Child VC interface
#protocol ANSearchGetawayFilterDelegate
-(void)selectedCell:(NSString *)cellTitle;
#end
#interface ANSearchGetawayFilterViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate>
{
NSString* cellTitle;
}
#property (nonatomic, assign) id<ANSearchGetawayFilterDelegate> delegate;
#end
//Child VC implementation
#implementation ANSearchGetawayFilterViewController
#synthesize delegate = _delegate;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
cellTitle = selectedCell.textLabel.text;
[[self delegate] selectedCell:cellTitle];
[self dismissModalViewControllerAnimated:YES];
}
//Parent VC interface
#import "ANSearchGetawayFilterViewController.h"
#interface ANGetawayFilterViewController : UIViewController <ANSearchGetawayFilterDelegate>
{
NSString* _cellText;
}
//Parent VC Implementation
- (id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
// Custom initialization
ANSearchGetawayFilterViewController *search = [[ANSearchGetawayFilterViewController alloc] init];
search.delegate = self;
}
return self;
}
//delegate method
-(void)selectedCell:(NSString *)cellTitle
{
_cellText = cellTitle;
NSLog(#"cell text %#", _cellText);
}
the delegate method is never called and when is NSLog the _cellText else where it comes up as null...what am I doing wrong? Thanks!
You are most likely creating a new instance of ANSearchGetawayFilterViewController when you present it and not configuring the delegate on it.
When you called
ANSearchGetawayFilterViewController *search = [[ANSearchGetawayFilterViewController alloc] init];
search.delegate = self;
you created an instance of ANSearchGetawayFilterViewController and then set the delegate up correctly, but you never stored this instance of ANSearchGetawayFilterViewController anywhere. So later on when you come to present it you call again
ANSearchGetawayFilterViewController *search = [[ANSearchGetawayFilterViewController alloc] init];
which gives you a completely different instance, which you then need to configure again. For example
ANSearchGetawayFilterViewController *search = [[ANSearchGetawayFilterViewController alloc] init];
ANSearchGetawayFilterViewController *search1 = [[ANSearchGetawayFilterViewController alloc] init];
NSLog(#"%d", search1 == search);
#=> 0
To fix update your code to be
- (BOOL)textFieldShouldBeginEditing:(UITextField*)textField;
{
BOOL shouldBeginEditing = YES;
NSLog(#"text field should begin editing");
ANSearchGetawayFilterViewController *myANSearchGetawayFilterViewController = [[[ANSearchGetawayFilterViewController alloc] init] autorelease];
myANSearchGetawayFilterViewController.delegate = self; // <--- configure the delegate
[self presentModalViewController:myANSearchGetawayFilterViewController animated:YES];
[self closeAllPickers];
return shouldBeginEditing;
}
I wouldn't make it an ivar as the likelihood is you will present this viewController momentarily just to select some data and then get rid of it, so it is probably safe to discard it and make a new one each time.
Au contraire, the delegate method is being called (hence the NSLog()). However, _cellText is (null) because the value being passed in is nil, ergo selectedCell.textLabel.text.
Firstly, are you sure that the -selectedCell method is being called?
You can do this by putting an NSLog() before or after -tableViewDidSelectRow...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
...
NSLog(#"TABLEVIEW DID SELECT ROW BEFORE -> %# <-", cellTitle);
[[self delegate] selectedCell:cellTitle];
NSLog(#"TABLEVIEW DID SELECT ROW DELEGATE CALLED");
...
}
Also, you might want to do some cleanup (optional)
Firstly, you are leaking in your initialisation method. Either set the ANGetawayFilterViewController as a property of the parent class using the delegate, or release it after you set the delegate.
Secondly, in the -tableViewDidSelectRow, your code assumes that the delegate has the -selectedCell method coded. If you don't have the method implemented, then the application will result in a crash. You can prevent this by checking to see if the delegate -respondsToSelector...:
if ([self.delegate respondsToSelector:#selector(selectedCell:)]) {
[self.delegate selectedCell:cellTitle];
}
Thirdly, the method of which is being called by the delegate to notify the parentViewController doesn't follow the general schema that delegate methods use, with the exception of -numberOfRowsInSection (UITableViewDelegate). Your method should contain the actual ANFilterGetawayViewController instance too:
- (void) filterGetawayViewController:(ANSearchGetawayFilterViewController *) controller didSelectCellWithTitle:(NSString *) title {
...
}
It can be called as such:
[self.delegate filterGetawayViewController:self didSelectCellWithTitle:cellTitle];
Are you using ARC? Because when the init function ends, your object (and it's reference to the delegate) are cleaned up. What happens if you make the search variable a global one (defining it in your header and initializing it in your code)?
Assuming you are using ARC:
You need to make a retained #property for your ANSearchGetawayFilterViewController instance. It will have been released by ARC by the time the delegate method is called. Do something like this.
#property (strong, nonatomic) ANSearchGetawayFilterViewController *search;
...
#synthesize search = _search;
- (id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
// Custom initialization
self.search = [[ANSearchGetawayFilterViewController alloc] init];
self.search.delegate = self;
}
return self;
}
Not related to your problem, but best practice is to check if the delegate actually implements the method you expect it to before calling it, like so:
if ([self.delegate respondsToSelector:#selector(selectedCell:)]) {
[self.delegate selectedCell:cellTitle];
}
I've reviewed (and tried) a bunch of the threads here regarding Singletons and NSMutableArrays. I'm new to Objective-C so please bear with me.
I simply want to create a few arrays that can be accessed from any view/.m file.
What is the best (or most concise) coding for a Singleton?
Below is what I have now and I get
1 warning at .m '#implementation' - "Incomplete implementation"
1 error at usage in a view .m file - "initializer element is not a compile-time constant"
This is the code I have now - my GlobalData.h file:
#import <Foundation/Foundation.h>
#interface GlobalData : NSObject {
NSMutableArray *listOfHeadings;
NSMutableArray *listOfItems1;
NSMutableArray *listOfItems2;
}
#property(nonatomic,retain)NSMutableArray *listOfHeadings;
#property(nonatomic,retain)NSMutableArray *listOfItems1;
#property(nonatomic,retain)NSMutableArray *listOfItems2;
+(GlobalData*)getInstance;
#end
My GlobalData.m file:
#import "GlobalData.h"
#implementation GlobalData
#synthesize listOfHeadings;
#synthesize listOfItems1;
#synthesize listOfItems2;
static GlobalData *instance=nil;
+(GlobalData *)getInstance
{
#synchronized(self)
{
if(instance==nil)
{
instance= [GlobalData new];
}
}
return instance;
}
#end
And in a view .m file (simplified):
#import GlobalData.h
GlobalData *globDat=[GlobalData getInstance]; //error occurs here
Can someone point out the trouble and if there's better coding, please enlighten me - thanks!
EDIT
Here's a few links I've tried to use:
Can i have a single NSMutableArray in my multiple views application?
iPhone help with singleton class
In this case, you might be doing more than you have to. Granted this certainly isn't always the best solution - but you can put your NSMutableArray as a property in your App Delegate and then easily refer to it from any view. By doing it this way - you aren't locking it in as a 'singleton' but there is a 'singleton instance' of it (this helps a great deal for testability).
I have simplified this process here:
YourAppDelegate.h
#property (nonatomic,retain) NSMutableArray *myArray;
YourAppDelegate.m
#synthesize myArray;
YourViewController.m
YourAppDelegate *appDelegate = (YourAppDelegate *)[[UIApplication sharedApplication] delegate];
NSMutableArray *myArrayFromAppDelegate = appDelegate.myArray;
From this point - you can do any manipulation on this value.
Here's the "modern" version of a single method to turn any class into a Singleton (in this case formatted as a code snippet). It works in iOS4.x or higher:
+(<#SingletonClassName#> *) sharedInstance
{
static <#SingletonClassName#> *_sharedClient = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedClient = [[self alloc] init];
});
return _sharedClient;
}
But, do you really need a singleton of a single NSMutableArray? You could use the built-on singleton - your application delegate, which is got to by calling:
MyAppDelegate * appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.myMutableArray addObject:...];
The error initializer element is not a compile-time constant is not related to how you create your singleton. The error is how you are accessing your singleton. You are doing this outside of a function:
GlobalData *globDat=[GlobalData getInstance];
This means that you are trying to initialize a global variable (globDat) as the value of the expression [GlobalData getInstance]. You can only initialize global variables to expressions that are "compile-time constants". That means things like 0 or "fred" or 8/2. The value of [GlobalData getInstance] cannot be computed at compile-time, so it cannot be used to initialize the global variable.
Instead, you need to just use [GlobalData getInstance] inside your function bodies wherever you are currently trying to use the globDat variable.
As for the warning, Incomplete implementation, I don't see what's missing. Perhaps you didn't post all of the code from GlobalData.h. Anyway, you should be able to click the warning (where it appears on the right side of the editor window) and have Xcode show you what's missing.
This is the way I create my Singleton:
Singleton.h
#import <Foundation/Foundation.h>
#interface Singleton : NSObject {
NSMutableArray *firstMutableArray;
NSMutableArray *secondMutableArray;
}
#property (nonatomic, retain) NSMutableArray *firstMutableArray;
#property (nonatomic, retain) NSMutableArray *secondMutableArray;
+ (id)sharedSingleton;
#end
Sigleton.m
#import "Singleton.h"
static Singleton *sharedMySingleton = nil;
#implementation Singleton
#synthesize firstMutableArray;
#synthesize secondMutableArray;
#pragma mark Singleton Methods
+ (id)sharedSingleton {
#synchronized(self) {
if (sharedMySingleton == nil) {
sharedMySingleton = [[super allocWithZone:NULL] init];
}
return sharedMySingleton;
}
+ (id)allocWithZone:(NSZone *)zone {
return [[self sharedSingleton] retain];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX;
}
- (oneway void)release {
// Never release
}
- (id)autorelease {
return self;
}
- (id)init {
if (self = [super init]) {
firstMutableArray = [[NSMutableArray alloc] initWithObjects:nil];
secondMutableArray = [[NSMutableArray alloc] initWithObjects:nil];
}
return self;
}
- (void)dealloc {
[firstMutableArray release];
[secondMutableArray release];
[super dealloc];
}
#end
Then, when you want to call your Singleton:
#import "Singleton.h"
Singleton *singleton = [Singleton sharedSingleton];
singleton.firstMutableArray = ...
singleton.secondMutableArray = ...
I have 4 classes i.e views in my application. Class A, having variable a and b.
After clicking on button which is on view A of class A it leads to class B, which is table view controller. Then class B leads to class C. then class C leads to class D.
Now i want to access values of a and b of class A into class D. I tried it with NSNotification but not succeeded.
Please suggest.
I tried with NSNotification:
i tried with NSNotification like Class A---
-(IBAction) selectButton:(id) sender{
NSString * a = [NSString stringWithFormat:#"Manjinder singh"];
NSDictionary * dict = [NSDictionary dictionaryWithObject:a forKey:#"1"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"sendMessage" object:self userInfo:dict];
}
Then Class D----
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(sendMessage:) name:#"sendMessage" object:nil];
}
return self;
}
-(void)sendMessage:(NSNotification *)notification{
A *dil=[[A alloc] init];
nslog(#"dil.a");
NSLog(#"USERINFO:MyUserInfo (its a dictionary):%#",[[notification userInfo] valueForKey:#"1"]);
}
This is the rendom try but basically i want to show variable a and b of class A into class D.
Update:------------
MyCoolViewController.h// a class where data send from
#protocol MyCoolViewDelegate;
#interface MyCoolViewController : UIViewController {
id <MyCoolViewDelegate> delegate;//
}
#property (nonatomic, assign) id delegate;//
#end
#protocol MyCoolViewDelegate <NSObject>//
-(void)sendAStringToAnotherView:(NSString*)string;
#end
MyCoolViewController.m
-(void)viewDidLoad{
[delegate sendAStringToAnotherView:#"this is a string"];
}
firstViewController.m //a class where data sent
-(void)viewDidLoad{
MyCoolViewController *myViewControllerPointer=[[MyCoolViewController alloc] init];
myViewControllerPointer.delegate = self;//
}
-(void)sendAStringToAnotherView:(NSString*)string
{
//displays the string as console output
NSLog(#"plzzzzzz show data",string);
}
value of string is not passed to this class because it is not showing in NSLog output.
UPDATED 2---
MyCoolViewController.m
#import “MyCoolViewController.h”
#import "firstViewController.h"
#implementation MyCoolViewController
#synthesize label1,sttr;
#synthesize delegate;//
-(IBAction) selectButton:(id) sender{
if (curri==nil) {
curri=[[CurrancyViewController alloc] initWithNibName:nil bundle:nil];
[self.navigationController pushViewController:curri animated:YES];
}
curri=nil;
//CHECK ThIS [curri release];
}
- (void)viewDidLoad
{
[delegate sendAStringToAnotherView:#"this is a string"];
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"background1.png"]];
[super viewDidLoad];
}
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
Can you give more context about what specifically you are trying to achieve? It sounds like you want to pass data between several UIViewControllers. Here is how to set up a delegate for one of your view controllers:
#import <UIKit/UIKit.h>
#protocol MyCoolViewControllerDelegate;
#interface MyCoolViewController : UIViewController {
id <MyCoolViewControllerDelegate> delegate;
}
#property (nonatomic, assign) id delegate;
#end
#protocol MyCoolViewControllerDelegate <NSObject>
-(void)sendAStringToAnotherView:(NSString*)string;
#end
Then you will should synthesize the delegate
#synthesize delegate;
and then when you want to pass data to, lets say a parent view, call this function:
[delegate sendAStringToAnotherView:#"this is a string"];
In the other view controller, wherever you instantiated the instance of this UIViewController, you need to set that self as the delegate;
myViewControllerPointer.delegate = self;
and then implement the delegate function in the parent view controller.
-(void)sendAStringToAnotherView:(NSString*)string
{
//displays the string as console output
NSLog(string);
}
The fact that you need communicate between views like this could possibly mean that there is a more efficient means of structuring your app. Can't say for sure without more info.
Try and use this template to add a delegate to your own app.
You could use delegation here
D would become the delegate of A, and when you click the button, A sends a message to D with the variables as arguments and D responds by performing a method.
I create a new "View-based Application" project and modify the didFinishLaunchingWithOptions: method as follow.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Add the view controller's view to the window and display.
[self.window addSubview:viewController.view];
[self.window makeKeyAndVisible];
downloader = [[InternetIOProcess alloc] init];
[downloader initWithServer:[NSURL URLWithString:#"http://www.test.com"] ];
return YES;
}
InternetIOProcess is a NSObject with two variables, and a method:
#interface InternetIOProcess : NSObject {
NSMutableArray* downloadingFile;
NSURL* serverAddress;}
#property (nonatomic,retain) NSMutableArray* downloadingFile;
#property (nonatomic,retain) NSURL* serverAddress;
-(void) initWithServer:(NSURL*) server;
the implementation of InternetIOProcess is:
#implementation InternetIOProcess
#synthesize downloadingFile,serverAddress; //,serviceuploadingQueue,;
-(void) initWithServer:(NSURL*) server
{
downloadingFile = [NSMutableArray array];
serverAddress = server;
}
And then, I write a IBAction in UIViewController response to a button "touch up inside" event:
-(IBAction) test:(id)sender
{
MyAppDelegate* d = (MyAppDelegate*)[UIApplication sharedApplication].delegate;
InternetIOProcess* thedownloader = d.downloader;
//value of "thedownloader" incorrect.
}
Try to access "thedownloader" here, its member "downloadingFile, serverAddress" both give random bad values!
Anybody know why can't I access this object?
The problem lies here with you not retaining the array and the server and bad naming convention of init. It looks like your custom init method is not getting called.
-(void) initWithServer:(NSURL*) server
{
downloadingFile = [NSMutableArray array];
serverAddress = server;
}
Try making the following changes
//InternetIOProcess.h add
-(id) initWithServer:(NSURL*) server;
//InternetIOProcess.m change
-(id) initWithServer:(NSURL*) server
{
self = [super init];
if(self != nil)
{
downloadingFile = [[NSMutableArray array] retain];
serverAddress = [server retain];
}
return self;
}
//MyAppDelegate.m
downloader = [[InternetIOProcess alloc] initWithServer:[NSURL URLWithString:#"http://www.test.com"]];
Just checking, your UIViewController contains
#import "MyAppDelegate.h"
and
#import "InternetIOProcess.h"
And your MyAppDelegate contains
#import "InternetIOProcess.h"
Also, are you getting any compiler warnings?
Is downloader a property with the retain attribute on the delegate class? I don't see you specifying retain when you allocate the instance.
In your initWithServer: method, use self.downloadingFile and self.serverAddress so that the objects are retained.