I'm having a problem with storing and accessing objects with NSmutable array in app delegate. I have tried methods form other websites and stack overlay pages but yet no solution. I want to able to access the array data in another view. Currently nothing is working for me.
Heres my code.
AppDelegate.h :
#interface AppDelegate : UIResponder <UIApplicationDelegate>
{
NSMutableArray* sharedArray;
}
#property (nonatomic, retain) NSMutableArray* sharedArray;
ViewController.h :
#import "AppDelegate.h"
-(void)viewDidLoad{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSMutableArray *model = appDelegate.sharedArray;
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:#"hello" forKey:#"title"];
[dict setObject:#"urlhere" forKey:#"thumbnail"];
[model addObject:dict];
NSLog(#"submitted to array: %#",model);
}
Are you, at any point, initializing the sharedArray? The array must be instantiated before you can add objects to it. For example:
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
self.sharedArray = [NSMutableArray array];
return YES;
}
Having done that, now attempts to add objects to this array from your view controllers should succeed.
Unrelated, but you should not define instance variables for your properties. Let the compiler synthesize that for you, e.g.:
AppDelegate.h:
#interface AppDelegate : UIResponder <UIApplicationDelegate>
// {
// NSMutableArray* sharedArray;
// }
#property (nonatomic, retain) NSMutableArray* sharedArray;
#end
What you have is technically acceptable, but it's inadvisable because of possible confusion between this sharedArray instance variable and the what the compiler will synthesize for you (e.g. if you don't have a #synthesize line, the compiler will automatically create an instance variable called _sharedArray, with a leading underscore, for you). Even if you had a #synthesize line that ensured that the instance variable was correct, having the explicitly declared instance variable is simply redundant.
Related
Following a post of similar question (which doesn't work), I declared a instance of GCDAsyncSocket on AppDelegate.h
#import <UIKit/UIKit.h>
#class ViewController;
#class GCDAsyncSocket;
#interface AppDelegate : UIResponder <UIApplicationDelegate>
{
GCDAsyncSocket *asyncSocket;
}
#property (strong, nonatomic) UIWindow *window;
#property (nonatomic, retain) GCDAsyncSocket *asyncSocket;
#property (strong, nonatomic) ViewController *viewController;
#end
and do the socket initialization in AppDelegate.m
#import "AppDelegate.h"
#import "GCDAsyncSocket.h"
#import "ViewController.h"
#implementation AppDelegate
#synthesize asyncSocket;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
dispatch_queue_t mainQueue = dispatch_get_main_queue();
self.asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:mainQueue];
NSString *host = #"10.1.100.50";
uint16_t port = 3040;
NSError *error = nil;
if (![self.asyncSocket connectToHost:host onPort:port error:&error])
{
NSLog(#"Error connecting: %#", error);
}
char bytes[] = "run";
NSData* requestData = [[NSData alloc] initWithBytes:bytes length:sizeof(bytes)];
[self.asyncSocket writeData:requestData withTimeout:-1 tag:0];
return YES;
}
The I tried to access the socket from multiple view controllers by invoking:
GCDAsyncSocket *asyncSocket = [[[UIApplication sharedApplication] delegate] asyncSocket];
the code completion stops at [[UIApplication sharedApplication] delegate] without being able to suggest asyncSocket.
What should I do to make asyncSocket accessible in multiple view controllers when the instance of asyncSocket is being declared in AppDelegate? Thanks!
Here's my Xcode project file : http://bit.ly/PLe1Le
You are on the right track. And the application delegate is a great place for a socket connection. I think you're being tripped up by something relatively simple.
[[UIApplication sharedApplication] delegate] returns an id or generic object pointer to an object that conforms to the <UIApplicationDelegate> protocol. So code completion has no way of knowing that your application's delegate is an instance of your AppDelegate class.
Remember if you are in fact using an instance of AppDelegate to be your application's delegate then [[UIApplication sharedApplication] delegate] will return a pointer to your delegate, but it will be the generic pointer discussed above.
The simplest solution is to cast the pointer you receive back from [[UIApplication sharedApplication] delegate] to be a pointer of AppDelegate type.
For example:
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
// We now have a pointer to your app delegate that the compiler knows is an AppDelegate.
// So code completion will work and it will compile.
GCDAsyncSocket *socket = [myAppDelegate asyncSocket];
Or you can stack the calls to one statement. The syntax looks a little funky, but this is how it's done.
GCDAsyncSocket *socket = [(AppDelegate *)[[UIApplication sharedApplication] delegate] asyncSocket];
In the code below, I am trying to add objects to array. No error, but is not adding objects either. Sorry for asking this pretty basic question. Need help
The NS Object Definition
//DataDefinition.h
#import
#interface DataDefinition : NSObject
#property (nonatomic, retain) NSString *dataHeader;
#property (nonatomic, retain) NSMutableArray *dataDetails;
#end
The DataDefinition Implementation
#import "DataDefinition.h"
#implementation DataDefinition
#synthesize dataHeader;
#synthesize dataDetails;
#end
The Display header section
//DataDisplay.h
#import
#import "DataDefinition.h"
#interface DataDisplay : UITableViewController
#property (strong, nonatomic) NSMutableArray *dataSet;
#property (strong, atomic) DataDefinition *individualData;
#end
The Display implementation section
//DataDisplay.m
#import "DataDisplay.h"
#interface DataDisplay ()
#end
#implementation DataDisplay
#synthesize dataSet;
#synthesize individualData;
- (void)viewDidLoad
{
[super viewDidLoad];
individualData.dataHeader = #"Header1";
individualData.dataDetails = [[NSMutableArray alloc] initWithObjects:#"Header1-Detail1", #"Header1-Detail2", #"Header1-Detail3", nil];
//This didnot add
[dataSet addObject:individualData];
NSLog(#"Count of objects is %d:",[dataSet count]);
//Nor did this
dataSet = [[NSMutableArray alloc] initWithObjects:individualData, nil];
NSLog(#"Count of objects is %d:",[dataSet count]);
self.title = #"DataDisplay";
}
The issue is that individualData is never actually set to an instantiated object (in other words, it is never initialized).
These kinds of oversights are common due to Objective-C's non-error policy regarding sending messages to nil; it's perfectly legal and often useful principle. This means that your code will never complain until you try to pass it to some method which will crash if it sees nil. Unfortunately, you are using initWithObjects, which simply sees nil as the end of the (empty) list. If you had instead tried to use [NSArray arrayWithObject:individualData] you may have seen an error which would hint to you that you had nil instead of an object.
Note that setting properties on nil is particularly tricky, since it looks like you are simply dealing with a C-syle lvalue, when actually it translates to a message-send call at runtime:
individualData.dataHeader = #"Header1";
// is *literally* the same as:
[individualData setDataHeader:#"Header1"];
You can take your pick of solutions. The "cheap" way is to simply initialize it right there. The "better" way (usually) is lazy-instantiation (i.e. in the getter). Since the object is marked as atomic, you likely need to let the compiler write the getter for you, and just initialize it in viewDidLoad (or awakeFromNib, initWithCoder, or similar):
- (void)viewDidLoad
{
[super viewDidLoad];
self.individualData = [[DataDefinition alloc] init];
...
I have used iAd's before but only for apps with a single view controller. But I cannot seem to figure out how to create a global reference to the ad in the AppDelegate and fetch it from there for my separate view controllers (That's what I've read I'm supposed to do).
I've been searching for a tutorial on the matter, but for some reason I can't find anything relevant.
Any hints? Point me in the right direction? :)
TIA!
/Markus
In applications there is a adddelegate.h and .m file. You add iad in delegate.m file and create reference in other view :
in Appdelegate.h add delegate :
#interface AppDelegate : UIResponder
ADBannerView *bannerView;
#property (nonatomic, retain) ADBannerView *bannerView;
in Appdelegate.m :
#synthesize bannerView;
(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
bannerView = [[ADBannerView alloc]initWithFrame:CGRectZero];
bannerView.requiredContentSizeIdentifiers = [NSSet setWithObjects:ADBannerContentSizeIdentifierLandscape,nil];
bannerView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierLandscape;
bannerView.delegate = self;
}
Now you create reference of Appdelegate in other class viewdidload :
AppDelegate *appdelegate = (AppDelegate *)[[UIApplication sharedApplication ]delegate];
UIView banner = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 480, 32)];
[banner addSubview:appdelegate.bannerView];
[self.view addSubview: banner];
I have one class that controls one window, and another class that controls a different window in the same xib, however, the second window never displays what it should.
In the first class I alloc and init the second class, then pass some information to it. In the second class it displays that data in the table view.
Yes, in the .xib I have all the connections set up correctly, I've quadruple checked. Also the code is correct, same with the connections, I've quadruple checked.
Edit: and yes, there's data in the arrays, and the classes are NSObjects.
Edit2: I kinda found the problem. For some reason, the array is filled with contents, but it's returning 0 as a count.
Edit 9000:
Here's the code:
Answer.h
#import <Cocoa/Cocoa.h>
#interface MSAnswerView : NSObject {
IBOutlet NSWindow *window;
NSArray *User;
NSArray *Vote;
NSArray *Text;
IBOutlet NSTableView *view;
IBOutlet NSTableColumn *voteCount;
IBOutlet NSTableColumn *saidUser;
IBOutlet NSTextView *body;
}
-(void)setUpWithVoteCount:(NSArray *)array User:(NSArray *)user Text:(NSArray *)text;
#property (nonatomic, retain) NSWindow *window;
#property (nonatomic, retain) NSTableView *view;
#property (nonatomic, retain) NSTableColumn *voteCount;
#property (nonatomic, retain) NSTableColumn *saidUser;
#property (nonatomic, retain) NSTextView *body;
#end
.m
#import "MSAnswerView.h"
#implementation MSAnswerView
#synthesize view;
#synthesize voteCount;
#synthesize saidUser;
#synthesize body;
#synthesize window;
-(void)awakeFromNib
{
[view setTarget:self];
[view setDoubleAction:#selector(bodydata)];
[view reloadData];
}
-(void)setUpWithVoteCount:(NSArray *)array User:(NSArray *)user Text:(NSArray *)text
{
Vote = array;
User = user;
Text = text;
if (window.isVisible = YES) {
[view reloadData];
[view setNeedsDisplay];
}
}
-(int)numberOfRowsInTableView:(NSTableView *)aTable
{
return [User count];;
}
-(id)tableView:(NSTableView *)aTable objectValueForTableColumn:(NSTableColumn *)aCol row:(int)aRow
{
if (aCol == voteCount)
{
return [Vote objectAtIndex:aRow];
}
else if (aCol == saidUser)
{
return [User objectAtIndex:aRow];
}
else
{
return nil;
}
}
-(void)bodydata
{
int index = [view selectedRow];
[body setString:[Text objectAtIndex:index]];
}
#end
The problems in your code are numerous.
For one thing, this comparison in -setUpWithVoteCount:User:Text: is incorrect:
window.isVisible = YES
That should be the comparison operator, == not the assignment operator =.
Secondly, you are naming your ivars and methods incorrectly. Instance variables (in fact, variables of any type) should start with a lower-case letter. This is to distinguish them from class names. Check out the Apple coding guidelines.
I'd also suggest that a name like text is a bad name for a variable that stores a collection like an NSArray. Instead, you should name it something like textItems so it's clear that the variable represents a collection and not a single string.
Also, the class itself is poorly named. You have called it MSAnswerView but it's not a view, it's some type of window controller. At the very least call it MSAnswerWindowController. Better still would be to make it a subclass of NSWindowController and make it File's Owner in its own nib. This is the standard pattern for window controllers.
Your method -setUpWithVoteCount:User:Text: should really be an initializer:
- initWithVoteCount:user:text:
That way it's clear what it's for and that it should be called once at object creation time.
The main problem, however, is that you're not retaining the values that you pass in to your setup method. That means that if no other object retains a reference to them, they will go away at some indeterminate point in the future. If you access them at a later time, you will crash or at the very least receive bad data, which is what's occurring.
Of course, you must also add a -dealloc method in this case to ensure you release the objects when you're finished with them.
Putting all those suggestions together, your class should really look something like this:
MSAnswerWindowController.h:
#import <Cocoa/Cocoa.h>
//subclass of NSWindowController
#interface MSAnswerWindowController : NSWindowController <NSTableViewDataSource>
{
//renamed ivars
NSArray *users;
NSArray *voteCounts;
NSArray *textItems;
IBOutlet NSTableView *view;
IBOutlet NSTableColumn *voteCount;
IBOutlet NSTableColumn *saidUser;
IBOutlet NSTextView *body;
}
//this is now an init method
- (id)initWithVoteCounts:(NSArray *)someVoteCounts users:(NSArray *)someUsers textItems:(NSArray *)items;
//accessors for the ivars
#property (nonatomic, copy) NSArray* users;
#property (nonatomic, copy) NSArray* voteCounts;
#property (nonatomic, copy) NSArray* textItems;
#property (nonatomic, retain) NSWindow *window;
#property (nonatomic, retain) NSTableView *view;
#property (nonatomic, retain) NSTableColumn *voteCount;
#property (nonatomic, retain) NSTableColumn *saidUser;
#property (nonatomic, retain) NSTextView *body;
#end
MSAnswerWindowController.m:
#import "MSAnswerWindowController.h"
#implementation MSAnswerWindowController
//implement the init method
- (id)initWithVoteCounts:(NSArray*)someVoteCounts users:(NSArray*)someUsers textItems:(NSArray*)items
{
//this is an NSWindowController, so tell super to load the nib
self = [super initWithWindowNibName:#"MSAnswerWindow"];
if(self)
{
//copy all the arrays that are passed in
//this means we hold a strong reference to them
users = [someUsers copy];
voteCounts = [someVoteCounts copy];
textItems = [items copy];
}
return self;
}
//make sure we deallocate the object when done
- (void)dealloc
{
self.users = nil;
self.voteCounts = nil;
self.textItems = nil;
[super dealloc];
}
//this is called when the window first loads
//we do initial window setup here
- (void)windowDidLoad
{
[view setTarget:self];
[view setDataSource:self];
[view setDoubleAction:#selector(bodydata)];
}
//this is called when the view controller is asked to show its window
//we load the table here
- (IBAction)showWindow:(id)sender
{
[super showWindow:sender];
[view reloadData];
}
- (NSInteger)numberOfRowsInTableView:(NSTableView*)aTable
{
return [users count];
}
- (id)tableView:(NSTableView*)aTable objectValueForTableColumn:(NSTableColumn*)aCol row:(NSInteger)aRow
{
if (aCol == voteCount)
{
return [voteCounts objectAtIndex:aRow];
}
else if (aCol == saidUser)
{
return [users objectAtIndex:aRow];
}
return nil;
}
- (void)bodydata
{
NSInteger index = [view selectedRow];
[body setString:[textItems objectAtIndex:index]];
}
#synthesize users;
#synthesize voteCounts;
#synthesize textItems;
#synthesize view;
#synthesize voteCount;
#synthesize saidUser;
#synthesize body;
#end
I'm trying to build an app where I have a TabBarController with 4 entries.
When I select the first entry, a view with a UITableView shows up.
This TableView is filled with several entries.
What I would like to do is:
When an entry out of that UITableView gets selected, another view should show up; a detailview.
.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0) {
if(self.secondView == nil) {
SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:#"SecondView" bundle:[NSBundle mainBundle]];
self.secondView = secondViewController;
[secondViewController release];
}
// Setup the animation
[self.navigationController pushViewController:self.secondView animated:YES];
}
}
.h
#import <UIKit/UIKit.h>
#import "SecondViewController.h"
#interface FirstViewController : UIViewController {
SecondViewController *secondView;
NSMutableArray *myData;
}
#property (nonatomic, retain) SecondViewController *secondView;
#property (nonatomic, copy, readwrite) NSMutableArray* myData;
#end
This is what I have so far.
Unfortunately.. the code runs, bit the second view does not show up.
Is your first view controller wrapped in a UINavigationController? When you set up your UITabBarController, you should add UINavigationControllers rather than your UIViewController subclasses, e.g.:
FirstViewController *viewControl1 = [[FirstViewController alloc] init];
UINavigationController *navControl1 = [[UINavigationController alloc] initWithRootViewController:viewControl1];
UITabBarController *tabControl = [[UITabBarController alloc] init];
tabControl.viewControllers = [NSArray arrayWithObjects:navControl1, <etc>, nil];
//release everything except tabControl
Also, based on your code, you don't need to keep your secondViewController as an ivar, since UINavigationController automatically retains its view controllers (and retaining it when you're not displaying it will use up unnecessary memory).