Instance method returns correct array from one view controller but null from others - objective-c

This is my first post so apologies for any errors I make, but this has been frustrating me for hours now and I cannot find a solution.
I have an app that uses a UITabBarViewController that has 3 tabs: FirstViewController, SecondViewController and ThirdViewController.
I have an NSObject class (Manager) where I reach out to from my view controllers to pull information from the calendar. Which works perfectly fine when I use the FirstViewController, however, when I go to use the other view controllers it simply returns "null" but I know the instance method is being called because I put an NSLog in the instance method it returns a value, but this value isn't being passed onto view controllers two and three.
The code I am using is below.
AppDelegate.m
#import <UIKit/UIKit.h>
#import "EventManager.h"
#interface AppDelegate : UIResponder <UIApplicationDelegate>{
}
#property (strong, nonatomic) UIWindow *window;
#property (nonatomic, strong) EventManager *eventManager;
#end
AppDelegate.m
- (void)applicationDidBecomeActive:(UIApplication *)application {
self.eventManager = [[EventManager alloc] init];
}
EventManager.h
#import <Foundation/Foundation.h>
#import <EventKit/EKEventStore.h>
#interface EventManager : NSObject
#property (nonatomic, strong) EKEventStore *eventStore;
-(NSMutableArray *) fetchCalendars;
#end
EventManager.m
-(NSMutableArray *) fetchCalendars {
NSArray *EKCalendars = [self.eventStore calendarsForEntityType:EKEntityTypeEvent];
NSMutableArray *mutableCalendars = [[NSMutableArray alloc] initWithArray:EKCalendars];
NSLog(#"EKCalendars %#",EKCalendars);
return mutableCalendars;
}
FirstViewController.m
-(void)loadCalendars{
NSMutableArray *mutableCalendars = [self.appDelegate.eventManager fetchCalendars];
}
This works absolutely fine for loading the calendars.
SecondViewController.m
-(void)loadCalendars{
NSMutableArray *mutableCalendars = [self.appDelegate.eventManager fetchCalendars];
}
This returns null, however, the output from the NSLog[ NSLog(#"EKCalendars %#",EKCalendars)] gives the exact same output as when it code is ran for the First View Controller.
I can get the calendars from the altering the SecondViewController.m to read
-(void)loadCalendars{
EventManager *per= [[EventManager alloc]init];
calendarsArray = [per fetchCalendars];
}
But I just don't understand why I need to reinitialize the event manager as it is initialized in the applicationDidBecomeActive.
Thanks for any help you guy can give.

You can access the Application's AppDelegate using [UIApplication sharedApplication].delegate:
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
NSMutableArray *mutableCalendars = [appDelegate.eventManager fetchCalendars];

Related

NSString works with one method but not the other

I have two different methods of trying to grab a variable from another class. The first one, which I would prefer using doesn't work - The second one, which I don't prefer does. Could someone please explain why?
AppDelegate.h
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate> {
NSString *someString;
}
#property (assign) IBOutlet NSWindow *window;
#property (retain, nonatomic) NSString *someString;
- (void)manualSetVariable;
#end
AppDelegate.m
#import "AppDelegate.h"
#import "GrabFromAppDelegate.h"
#implementation AppDelegate
#synthesize someString;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
someString = #"The Variable";
NSLog(#"In AppDelegate (1): %#",someString);
GrabFromAppDelegate *getThis = [[GrabFromAppDelegate alloc] init];
getThis.varSet = someString;
}
- (void)manualSetVariable { // THIS METHOD WORKS (2)
someString = #"The Variable";
NSLog(#"In AppDelegate(2): %#",someString);
}
#end
GrabFromAppDelegate.h
#import <Foundation/Foundation.h>
#interface GrabFromAppDelegate : NSObject {
NSString *varSet;
IBOutlet NSTextField *variable;
}
#property(retain, nonatomic) NSString *varSet;
- (IBAction)showVariable:(id)sender;
- (IBAction)manuallyGrabVariable:(id)sender;
#end
GrabFromAppDelegate.m
#import "GrabFromAppDelegate.h"
#import "AppDelegate.h"
#implementation GrabFromAppDelegate
#synthesize varSet;
- (IBAction)showVariable:(id)sender {
if (varSet != NULL) {
[variable setStringValue:[NSString stringWithString:varSet]];
NSLog(#"Got String Using (1): %#",varSet);
}
}
- (IBAction)manuallyGrabVariable:(id)sender { // THIS METHOD WORKS (2)
AppDelegate *getString = [[AppDelegate alloc] init];
[getString manualSetVariable];
if ([getString someString] != NULL) {
[variable setStringValue:[NSString stringWithString:[getString someString]]];
NSLog(#"Got String Using (2): %#",[getString someString]);
}
}
#end
This is horribly wrong:
AppDelegate *getString = [[AppDelegate alloc] init];
That allocates an AppDelegate instance, but it's not [[NSApplication sharedApplication] delegate], so the getString instance will never execute the applicationDidFinishLaunching method and your someString iVar will never get set. If you'd set someString within an init function, [[AppDelegate alloc] init] would, of course, call init. But since getString isn't attached to an NSApplication instance, there's nothing delegating the applicationDidFinishLaunching method to it.
If you want to get a pointer to the application delegate, you can do:
AppDelegate *getString = [[NSApplication sharedApplication] delegate];
or, for brevity's sake:
AppDelegate *getString = [NSApp delegate];
In second method you are calling method from app delegate and value is set at that time in someString variable and you get response. However if you are setting value for a varibale in appDelegate using an instance the set value will passed to that particular instance of controller class not to all instances. Hence either you create a shared instance of that variable or call that particular instance
to get the value somestring by showVariable method.

Obtaining the string value from separate window to be used on another. Objective C

I have a window with a large NSTextFeildCell, where text can be modified. Upon clicking a button another window appears where the text from the original window can be used some how. The issue I am having is when I attempt to retrieve that text the log spits out...
" -[NSTextView stringValue]: unrecognized selector sent to instance 0x100151860"
Fallowed by a long trace...
I have tried to solve this several different ways but with no luck.
currently,
First window controller
.h
#import <Cocoa/Cocoa.h>
#class NextWindowController;
#interface TextViewWindowController : NSWindowController
#property (nonatomic, weak) NextWindowController *NextWindow;
#property (nonatomic, weak) IBOutlet NSTextFieldCell *txtTextView;
- (IBAction)btnClicked:(id)sender;
- (NSString*)getText;
#end
.m
#import "TextViewWindowController.h"
#import "NextWindowController.h"
#implementation TextViewWindowController
#synthesize NextWindow;
- (IBAction)btnClicked:(id)sender{
[NextWindow setCallingWindow:self];
[NextWindow showWindow:self];
}
- (NSString*)getText{
return [_txtTextView stringValue];// there is a problem with the view...
}
#end
Next Window controller
.h
#import <Cocoa/Cocoa.h>
#class TextViewWindowController;
#interface NextWindowController : NSWindowController{
NSMutableString* str;
}
#property (nonatomic, weak) TextViewWindowController *callingWindow;
#end
.m
#import "NextWindowController.h"
#import "TextViewWindowController.h"
#implementation NextWindowController
#synthesize callingWindow;
- (IBAction)btnEnterClicked:(id)sender{
[str setString:callingWindow.txtTextView.stringValue];
}
- (id)initWithWindow:(NSWindow *)window{
self = [super initWithWindow:window];
if (self) {
str = [[NSMutableString alloc] init];
}
return self;
}
#end
I have also tried str = [callingWindow getText] with the same result.
Any help would be very appreciated!
It's not super intuitive to figure out from Apple's documentation, but to get the raw string value of a NSTextView (which inherits from NSText), just use:
[_txtTextView string];
And since you're using properties, it might be smarter to use the accessor in your function, like this:
- (NSString*)getText{
return [self.txtTextView string];
}

My own method isn't being found by the compiler

I recently started learning Objective-C and Cocos-2D. I tried to define my own method for automating the creation of sprites.
I added my own class where I'll create other automation methods as well. Anyhow my .h file looks like this:
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface ActionsClass : CCNode {
}
#property (nonatomic, strong) CCSprite* createSprite;
#property (nonatomic, strong) CCSprite* spriteName;
#property (nonatomic, strong) NSString* pngName;
#property (nonatomic) CGPoint* spriteCoordinate;
- (CCSprite *)createSprite: (CCSprite *)spriteName: (NSString *)pngName: (CGPoint *)spriteCoordinate;
#end
And the .m is:
#import "ActionsClass.h"
#implementation ActionsClass
#synthesize createSprite = _createSprite;
#synthesize spriteName = _spriteName;
#synthesize pngName = _pngName;
#synthesize spriteCoordinate = _spriteCoordinate;
- (CCSprite *)createSprite: (CCSprite *)spriteName: (NSString *)pngName: (CGPoint *)spriteCoordinate
{
if (!_createSprite)
{
_createSprite = [[CCSprite alloc] init];
_spriteName = [CCSprite spriteWithFile:_pngName];
_spriteName.position = ccp(_spriteCoordinate->x, _spriteCoordinate->y);
[self addChild:_spriteName];
}
return _createSprite;
}
#end
In the main .m file where I want to call the method:
[self createSprite: saif: #"saif.png": ccp(100,100)];
This would give the warning that xcode didn't find the instance method createSprite and defaults it to id
Thanks a lot and sorry if the font or the formatting of the question aren't super neat.
Your method declaration is wrong, so you wont be able to call it.
It should be:
- (CCSprite *)createSprite:(CCSprite *)spriteName pngName:(NSString *)pngName coord:(CGPoint *)spriteCoordinate;
And called like:
[self createSprite:someSprite pngName:somePNGName coord:someCoord];
Edit: I didn't see that you were trying to call this from another class. To do that you will need to import the ActionsClass header file, and call this method on an instance of ActionsClass, e.g.
ActionsClass *actionsClassObject = [[ActionsClass alloc] init];
[actionsClassObject createSprite:someSprite pngName:somePNGName coord:someCoord];

passing data between tabs in iOS

it is my first app that I am trying to do on my own and I have some questions. I want to have 4 tabs, and in the first one named "HomeView" I am parsing JSON data (this is done so far).
But what I want is some of the data that are being parsed to be visible in other tabs (and not have to parse them again).
So parts of my code of HomeView is here:
#import "HomeView.h"
#interface HomeView ()
#end
#implementation HomeView
//other code
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
//data fetched
parsed_date=[res objectForKey:#"date"];
NSLog(#"Date:%#",parsed_date);
[UIAppDelegate.myArray addObject:parsed_date];
}
and I can see the "parsed_date" being printed out correctly.
So I want this parsed_date to be visible in OtherView.
This is my code but I cannot print it out.
OtherView.m
#import "OtherView.h"
#import "HomeView.h"
#import "AppDelegate.h"
#interface OtherView ()
#end
#implementation OtherView
#synthesize tracks_date;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
//preview value of other class
tracks_date = [UIAppDelegate.myArray objectAtIndex:0];
NSLog(#"Dated previed in OtherView: %#", tracks_date);
}
and (null) is being printed out.
added code of app delegate.h
#import <UIKit/UIKit.h>
#define UIAppDelegate ((AppDelegate *)[UIApplication sharedApplication].delegate)
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (nonatomic, strong) NSArray *myArray;
#end
So can you suggest me a sollution?
Add the property to your Application Delegate instead.
When assigning the property do something like:
MyAppDelegate *delegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
delegate.myProperty = #"My Value";
then, in your different tabs, you can retrieve this property in the same manner:
MyAppDelegate *delegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
NSString *valueInTab = delegate.myProperty;
Uh, when you create a HomeView in your last code segment there, you're creating a new object -- a new instance of the class. It will not contain the data from connectionDidFinishLoading unless that method is executed in that instance of the class.
You basically need to use some sort of persistence mechanism to do what you want, either the AppDelegate or static storage along the lines of a "singleton".
While this may not be the best method of doing this, it is easy and effective.
Save your data in your app delegate and retrieve it from there. You can create a shortcut to your app delegate shared application. Then just access the values there.
AppDelegate.h
#define UIAppDelegate ((AppDelegate *)[UIApplication sharedApplication].delegate)
#property (nonatomic, strong) NSArray *myArray;
TabView1.m
#import "AppDelegate.h"
SomeObject *myObject = [UIAppDelegate.myArray objectAtIndex:0];
Like I said, it might not be the best way to organize your data for your application, this method does work for small amounts of data needing to be shared at the application level. Hope this helps.
this happens because you create an instance of HomeView yourself.
it has simply no connections to anything.
your first example works because it is the created and initialized from your nib.
i think the best way is to use an IBOutlet and then connect both 'Views' in InterfaceBuilder.
#interface OtherView ()
IBOutlet HomeView *homeView;
#end
#implementation OtherView
#synthesize tracks_date;
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Dated previed in OtherView: %#", homeView.parsed_date);
}
- (void)dealloc:
{
[homeView release];
}
have a look here, it will demonstrate it much more
In InterfaceBuilder you can manage your Objects and connect them (via IBOutlets and IBAction, ...) together.
I think this video is a good demonstration how this concept work.

Why is my NSDictionary not initializing my specific keys and values when in my model, but works within my controller?

In this example my NSDictionary initializes with 0 key/value pairs, as shown in my debugger. It will initialize properly when I do the exact same thing in my ViewController but I would much prefer to stick to MVC design and have the NSDictionary in my model.
ShakespeareViewController.h
#import <UIKit/UIKit.h>
#interface ShakespeareViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *sonnetDisplay;
#end
ShakespeareViewController.m
#import "ShakespeareViewController.h"
#import "ShakespeareModel.h"
#interface ShakespeareViewController ()
#property (nonatomic, strong) ShakespeareModel *sonnet;
#end
#implementation ShakespeareViewController
#synthesize sonnetDisplay = _sonnetDisplay;
#synthesize sonnet = _sonnet;
- (IBAction)sonnetButton:(UIButton *)sender
{
self.sonnetDisplay.text = [self.sonnet grabSonnet:#"19"];
}
#end
ShakespeareModel.h
#import <Foundation/Foundation.h>
#interface ShakespeareModel : NSObject
-(NSString *)grabSonnet:(NSString *)atNumber;
#end
ShakespeareModel.m
#import "ShakespeareModel.h"
#interface ShakespeareModel()
#property (nonatomic, strong) NSDictionary *sonnets;
#end
#implementation ShakespeareModel
#synthesize sonnets = _sonnets;
-(NSDictionary *)sonnets
{
if (!_sonnets)
{
_sonnets = [[NSDictionary alloc] initWithObjectsAndKeys:#"19", #"19", nil];
}
return _sonnets;
}
-(NSString *)grabSonnet:(NSString *)atNumber
{
NSString *chosenSonnet = [self.sonnets objectForKey:#"19"];
return chosenSonnet;
}
#end
Any ideas on what I am doing wrong are greatly appreciated. I can't see why this wouldn't initialize with the object 19 at key value 19.
I don't see any place where you set the view controller's sonnet property to an instance of ShakespeareModel -- so when you call grabSonnet: you're sending a message to nil (and thus getting nothing back.
You should put self.sonnet = [[ShakespeareModel alloc] init] in your view controller some time before you call grabSonnet:... probably in the initializer or in -viewDidLoad.