I used the codes below to set a NSString
#import <Foundation/Foundation.h>
#interface AppController : NSObject
{
NSString *myString;
}
#property (nonatomic, retain) NSString *myString;
#end
#import "AppController.h"
#implementation AppController
#synthesize myString;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSString *zs0= [[NSString alloc] initWithFormat: #"abc"];
myString =[zs0 retain];
[zs0 release];//breakpoint
}
- (void)dealloc {
[myString release];
[super dealloc];
}
#end
when I check the value of myString at the breakpoint
it always said 'out of scope'
Welcome any comment
You don't need the temp variable zs0 - just assign it to the property
You don't need initWithFormat since you're not formatting.
You don't need to alloc the string - if you call [NSString stringWithString] it will autorelease it and then when you assign it to a (retain) property, it will retain it.
You're over retaining. You alloc the string which gives it a retain count of 1, then you retain it which gives it 2, then you assign it to a retained property which retains it again.
One simple way is:
self.myString = [NSString stringWithString:#"abc"];
That will create a string that's autoreleased (not created with alloc, copy by convention) and then the property will retain it.
Why are you using initWithFormat if you aren't using a format?Next, why even allocate zs0 if you aren't going to use it? Just set myString to what you want it to be.
Thus, your code should look like this:
myString = [[NSString alloc] initWithString: #"abc"];
Try that and everything should work.
Related
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.
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 wrote a Cocoa Application and I got EXC_BAD_ACCESS error when I'm closing an application window. I read that this error usually means problems with memory, but I have ARC mode on and I don't need care about releasing e.t.c. (xCode forbids me to call this functions and manage memory automatically).
Error is pointing at line return NSApplicationMain(argc, (const char **)argv); in main function.
Here's my application's code:
.h file:
#interface MainDreamer : NSWindow <NSWindowDelegate>
{
NSTextField *dreamField;
NSTableView *dreamTable;
NSImageView *dreamview;
NSMutableArray *dreamlist;
NSMutableArray *dataset;
}
#property (nonatomic, retain) IBOutlet NSTextField *dreamField;
#property (nonatomic, retain) IBOutlet NSTableView *dreamTable;
#property (nonatomic, retain) IBOutlet NSImageView *dreamview;
#property (nonatomic, retain) IBOutlet NSMutableArray *dreamlist;
#property (nonatomic, retain) IBOutlet NSMutableArray *dataset;
#property (assign) IBOutlet NSWindow *window;
#end
.m file:
#implementation MainDreamer
#synthesize window;
#synthesize dataset;
#synthesize dreamField;
#synthesize dreamlist;
#synthesize dreamview;
#synthesize dreamTable;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification{
NSString *applicationPath = [[NSBundle mainBundle] bundlePath];
NSString *filename = [applicationPath stringByAppendingPathComponent:#"dreams"];
NSLog(self.description);
dreamlist = [[NSMutableArray alloc] init];
dataset = [[NSMutableArray alloc] init];
dataset = [NSKeyedUnarchiver unarchiveObjectWithFile:filename];
if([dataset count] != 0) {
int i = 0;
while (i < [dataset count]) {
Dream *dr = [[Dream alloc] init];
dr = [dataset objectAtIndex:i];
[dreamlist addObject: dr.dreamname];
i++;
}
}
[dreamTable reloadData];
}
-(void)applicationWillTerminate:(NSNotification *)notification{
NSString *applicationPath = [[NSBundle mainBundle] bundlePath];
NSString *filename = [applicationPath stringByAppendingPathComponent:#"dreams"];
[NSKeyedArchiver archiveRootObject:dataset toFile:filename];
NSLog(#"finish");
}
- (void) mouseUp:(NSEvent *)theEvent{
long index = [dreamTable selectedRow];
Dream *dr = [[Dream alloc] init];
dr = [dataset objectAtIndex:index];
dr.dreampicture = dreamview.image;
[dataset replaceObjectAtIndex:index withObject:dr];
NSLog(self.description);
}
- (void) tableViewSelectionDidChange: (NSNotification *) notification{
long row = [dreamTable selectedRow];
Dream *dr = [[Dream alloc] init];
dr = [dataset objectAtIndex: row];
if(dr.dreampicture != NULL)
dreamview.image = dr.dreampicture;
NSLog(#"selected row changed");
}
Class "Dream":
#interface Dream : NSObject <NSCoding>
{
NSString *dreamname;
NSImage *dreampicture;
}
#property (retain) NSString* dreamname;
#property (retain) NSImage* dreampicture;
-(id)initWithCoder:(NSCoder *)aDecoder;
-(void)encodeWithCoder:(NSCoder *)aCoder;
#end
What is wrong, why EXC_BAD_ACCESS occurs?I remind that I have xCode 4 with Automatic Reference Counting (ARC)
Thanks
UPDATE
I used Profile to find zombie event. So I found out this: An Objective-C message was sent to a deallocated object(zombie( at adress 0x108d85230)
Responsible Caller - [NSApplication(NSWindowCache) _checkForTerminateAfterLastWindowClosed: saveWindows:]
I had this function in code:
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender{
return TRUE;
}
However after I putted it in comments, this zombie event continue to occur.
The crash is caused by the fact that you made the window your application's delegate. When you close the window, that is the last release that kills it off, and if it's the last window you had up, it causes the application to ask its delegate whether it should quit. Since the window you just killed off is the application's delegate, you get that crash.
Longer explanation and suggestion of solution in my answer on your subsequent question.
This is wrong:
dataset = [[NSMutableArray alloc] init]; // WRONG
dataset = [NSKeyedUnarchiver unarchiveObjectWithFile:filename];
Why? You first allocate an empty array, and store that in the instance variable dataset. But in the next line, you replace the empty array with whatever +unarchiveObjectWithFile: returns. Why is this a problem? Well, if you read the docs, you'll see that it returns nil if the file is not found. This means that you now replace the empty array with nil, and all messages you send to dataset will be ignored (messages to nil are silently ignored in Objective-C)
I assume you actually want load the dataset from file, and only if that failed, start with an empty dataset:
dataset = [NSKeyedUnarchiver unarchiveObjectWithFile:filename];
if (dataset==nil) dataset = [[NSMutableArray alloc] init];
You have a similar error later on:
Dream *dr = [[Dream alloc] init]; // WRONG
dr = [dataset objectAtIndex:index];
You create a Dream object, and then replace it immediately with something from the dataset. What you actually want to do is:
Dream *dr;
dr = [dataset objectAtIndex:index];
or shorter:
Dream *dr = [dataset objectAtIndex:index];
Then again, you could replace the while loop with a fast-enumeration-style for loop:
for (Dream *dr in dataset) {
[dreamlist addObject: dr.dreamname];
}
Finally, to get to a point, I don't think the EXC_BAD_ACCESS actually occurs in main.h. I assume you use Xcode 4. Please use the thread/stack navigator in the right sidebar when debugging to find the actual position where the error occurs.
It could be that the error actually occurs in applicationWillTerminate:, because you try to archive dataset, which is probably nil, and it's probably not allowed to archive nil.
With ARC you should use strong and weak instead of retain and assign.
I was to pass a NSString from RootViewController(UITableViewController) to DetailViewController .
t RootViewController.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
DetailViewController *detailViewController = segue.destinationViewController;
detailViewController.name = #"foo";
}
DetailViewController.h:
NSString *name;
#property (nonatomic,strong) NSString *name;
DetailViewController.m
#synthesize name = _name;
NSLog(#"%#", name);
The result of NSlog is null. Appreciate for any hint. Thanks a lot.
I can't really see when you are executing your nslog. So i'm thinking you ask for the name before you are setting it.
And another thing. If you write:
#synthesize name = _name;
you should use this too:
NSLog(#"%#", _name);
you can view the sample passing data from cell to detailViewController at YouTube.
Is there a way to nicely print dictionaries in XCode during debugging? Selecting print description to console is ugly.
You should use a Category on NSDictionary and override - (NSString *)description.
(This way it automagically applies to all your existing NSDictionaries)
Below is a sample formatting, but you could change it to look like anything you want.
// NSDictionary+NicePrint.h
#import <Foundation/Foundation.h>
#interface NSDictionary (NicePrint)
#end
// NSDictionary+NicePrint.m
#import "NSDictionary+NicePrint.h"
#implementation NSDictionary (NicePrint)
- (NSString *)description
{
NSMutableString *output = [[NSMutableString alloc] init];
[self enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
[output appendFormat:#"%# => %#\n", key, obj];
}];
return [NSString stringWithString:output];
}
#end
You could subclass NSDictionary and override the -(NSString*)description function of NSObject.
Take you 5 minutes.