Passing a reference and copying the object from another controller. Objects keep disappearing - objective-c

I know this is a relativly easy question, but I just can't figure out how to solve this problem:
One of my views will receive a dragOperation and the performDragOperation method should pass the NSURL to my AppDelegate which puts it in an mutArray...
The problem is, that I pass over a reference and the object disappears the moment performDragOperation is done. So I tried several things:
in performDragOperation:
//Puts the reference itself in the folderPaths Array
AppDelegate *appDelegate = [NSApp delegate];
[[appDelegate folderPaths] addObject:referenceTotheNSURLObject];
/* tried creating a NSString and putting it in too. Same result because local variables will disappear */
So I created a method in AppDelegate and tried different things:
- (void)addFilePath:(NSURL *)filePath {
NSURL *copyOfURL = [filePath copy];
[[self folderPaths] addObject:copyOfURL];
}
This makes the most sense to me and the only reason I can think about why this doesn't work is, because copyOfURL itself is a pointer and it points to an localObject that will disappear the moment the addFilePath method is finished? But I'm not allowed to use
NSURL copyOfURL = [filePath copy];
I also tried recreating an NSString object again. Same results.
- (void)addFilePath:(NSURL *)filePath {
NSString *pathString = [filePath absoluteString];
[[self folderPaths] addObject:pathString];
}
I know it will be some relatively simply solution but I'm stuck and can't figure it out. Thanks for your time!

Related

Unrecongized Selector sent to Instance

Ive been through similar questions on here, but can't seem to relate it to my app!
My problem is when i run the program i get at error message
[UIView setAttString:]: unrecognised selector sent to instance 0x7538c60
Ive debugged the code down to 3 lines in the ViewController class - these are:
NSString *path = [[NSBundle mainBundle] pathForResource:#"g1" ofType:#"txt"];
NSAttributedString* text = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL];
[(CTView*)self.view setAttString: text];
Im pretty sure its with the final line, but as this line has been lifted from an example app I haven't really grasped the proper understanding of what it does, and therefore can't see anything wrong with it! Any obvious or common errors I could try to resolve? I don't know how much of my code is needed for the clever folk out there to help me out - let me know and I can add more snippets!
Thanks in advance!
In human terms, that snippet is loading a string from your app's resource file, then sending it to the object referenced by self.view by means of the setAttrString: message.
The error you're seeing shows up when an object receives a message that it doesn't recognize. I don't know what a CTView is, but you should ensure that:
The CTView class does actually have a method called setAttrString:
The object referenced by self.view is actually an instance of CTView.
You can verify that latter with the following:
BOOL isCorrectClass = [self.view isMemberOfClass:[CTView class]];
...or just look at it in the debugger at runtime.
Looks like CTView response to setAttString, but your self.view is a UIView instead of CTView. And usually the self.view of a viewController is just a UIView.
If you created the view as an outlet in your IB, make sure you set it to be CTView class.
Or share where did you alloc inited the "self.view" in your last line of code.

My NSString is determined to equal null, infuriating

This has been bugging me all night, It doesn't make any sense. This function returns whatever it's supposed to. EG, the issueName.
-(id)initWithIssue:(NSString *)string {
self = [super initWithNibName:nil bundle:nil];
if (self) {
NSString *thing = string;
issueName = [[NSString alloc]initWithString:thing];
NSLog(#"The issue name = %#", issueName);
}
return self;
}
However if I try to access 'issueName' in the viewDidLoad: nothing, it's equal to null no matter what I do. I've tried cleaning, setting a custom setter, switching between a property or a Ivar... ect. What's so infuriating is that this string just disappears at this point in the programe.
What the hell is going on, this is infuriating.
Edit
This the the entire code that is relevant. And how I started off.
Dot h file:
#interface BFPaidAreaViewController : UITabBarController <BFNewsTableViewControllerDelegate> {
NSString *issueName;
}
-(id)initWithIssue:(NSString *)string;
Dot m file:
-(id)initWithIssue:(NSString *)string {
self = [super init];
if (self) {
// PLPiper I had it that way before, because I was fiddling out of frustration
issueName = [[NSString alloc] initWithString:string];
NSLog(#"This is Called, the issue name is equal to = %#", issueName);
}
return self;
}
-(void)viewDidLoad {
[super viewDidLoad];
NSLog(#"The issue = %#", issueName);
}
I'm calling the view controller like so:
BFPaidAreaViewController *pavc = [[BFPaidAreaViewController alloc]initWithIssue:#"test"];
This will log:
This is Called, the issue name is equal to = test
The issue = (null)
New Edit
Found the problem. It's a UITableViewController. Strange, when I change it's class to a UIViewController it works. Is this a bug or just normal behaviour? But more pressing, how to I get round this limitation?
(Just to explain what I've done UI wise, the UITabBarController is in a modal View. This works fine with a UIViewController.)
God Awful Fix
-(id)initWithIssue:(NSString *)string {
self = [super initWithNibName:nil bundle:nil];
if (self) {
NSString *thing = string;
issueName = [[NSString alloc]initWithString:thing];
NSLog(#"The issue name = %#", issueName);
}
[self viewDidLoad];
return self;
}
Makes me feel dirty. But it will have to do for now, I can continue. If anyone can think of a solution please tell. Sorry about my feistiness, it was incredibly frustrating listening to people say, 'what the hell is this?? what is issueName?? an ivar??' when it was really implicit in the question.
Okay, first of all, replace:
self = [super initWithNibName:nil bundle:nil]; // Unneeded nil arguments
with:
self = [super init]; // Equivalent method, less processing involved.
Secondly, replace:
NSString *thing = string;
issueName = [[NSString alloc]initWithString:thing];
with just:
_issueName = [[NSString alloc] initWithString:string];
If issueName is a property (and you haven't #sythesized it to anything else) its representation should be _issueName.
The above fixes are more or less just make the code more succinct. The issue is probably with the code in viewDidLoad: (See below).
Now you can initialise your Issue object, and use the following code to display the issue name:
// Init:
Issue *myIssue = [[Issue alloc] initWithIssue:#"Example Issue"];
// Log:
NSLog(#"%#", myIssue.issueName);
And the log should show:
Example Issue
can you try this:
make the issueName a property, like
#property (strong, nonatomic) NSString *issueName;
then use it like this,
-(id)initWithIssue:(NSString *)string {
self = [super initWithNibName:nil bundle:nil];
if (self) {
NSLog(#"The string = %#", string);
self.issueName = string;
NSLog(#"The issue name = %#", issueName);
}
return self;
}
if you are using the automated synthetized property (i.e not declaring the #synthentize manually for the issueName), then your iVar will be called _issueName instead of issueName
what do you get from the above code ?
I find this somewhat curious. You call [super initWithNibName:nil bundle:nil]. This leads me to believe that this might be a subclass of NSViewController. If you init an NSViewController like this, barring some other, pretty non-standard stuff, -viewDidLoad probably won't get called because there's no NIB to be loaded (because you passed nil to super). But clearly you're setting a breakpoint in -viewDidLoad so it's getting called (on something). This makes me think that you have this class specified in a XIB somewhere as a File's Owner or as a NIB-loaded custom object. If that's the case, it leads me to believe that the instance you're init-ing and the instance on which -viewDidLoad is being called aren't the same instance. You can confirm this for yourself by putting NSLog(#"self: %p", self); in each method and seeing whether they are the same or different.
If the instance that is getting a call to -viewDidLoad is NIB-loaded, then your init method won't be called. Instead it will use -initWithCoder
If you can elaborate on the situation here (i.e. how this is getting instantiated, are there any XIBs involved, etc), I will edit my answer to provide more help, but I don't think there's enough information here to be truly helpful.
I feel your frustration. Assuming standard behavior, any of the suggestions here should have worked. This only reinforces my suspicion that these are not the same instance (between -initWithIssue and -viewDidLoad.

NSString instance variable crash

I was on a roll learning objective-c, but I just don't get this. I'm declaring an nsstring i-var, i set the value in the init method, and then when I access that ivar in a later instance method, it crashes or behaves unpredictably.
//heres what my declaration looks like
#interface StockData : CCNode {
NSString *myPath;
NSString *myPath2;
}
-(id) init
{
if ( (self = [super init]) ){
myPath = [[NSBundle mainBundle] pathForResource:#"stocks" ofType:#"sqlite"];
myPath2 = #"test";
CCLOG(#"mypath::::%#",[myPath class]);
CCLOG(#"mypath2::::%#",[myPath2 class]);
}
return self;
}
-(void) getChunk{
CCLOG(#"mypath_getchunk::::%#",[myPath class]);//this crashes
CCLOG(#"mypath2_getchunk::::%#", [myPath2 class]);//this doesn't
....
i am using cocos2d, and I am calling getChunk method in an scheduled update method like this:
-(void) updateOncePerSecond:(ccTime)delta{
if(!sd){
sd = [StockData initStockData];
[self addChild:sd];
}
[sd getChunk];
NSLog([sd getDate]);
}
the first time it iterates through I get this:
2012-03-19 20:33:58.591 HelloWorld[6777:10a03] mypath_getchunk::::__NSCFString
2012-03-19 20:33:58.591 HelloWorld[6777:10a03] mypath2_getchunk::::__NSCFConstantString
the second time it iterates through(if it doesn't crash):
2012-03-19 20:33:59.589 HelloWorld[6777:10a03] mypath_getchunk::::NSMallocBlock
2012-03-19 20:33:59.589 HelloWorld[6777:10a03] mypath2_getchunk::::__NSCFConstantString
why does it crash sometimes, and not other times. Why is it turning into a mallocblock? Are NSString's buggy, or am I doing it wrong. other variables seem to be working fine? How can I get my NSCFString to behave like that NSCFConstantString. I like that one better cause it doesn't crash. Any advice would be much appreciated!!!
thanks!
The string pathForResource:ofType: is autoreleased, which means it will be released “sometime later”. If you want to keep it alive, retain it:
myPath = [[[NSBundle mainBundle] pathForResource:#"stocks" ofType:#"sqlite"] retain];
And don't forget to release it later in dealloc.

Why is my variable out of scope?

I have an NSMutableArray defined in my AppDelegate class:
NSMutableArray *devices;
I populate the array from a class in the didFinishLaunchingWIthOptions method:
Devices *devs = [[Devices alloc] init];
self.devices = [devs getDevices];
The getDevices method parses a json string and creates a Device object, adding it to the array:
NSMutableArray *retDevices = [[NSMutableArray alloc] initWithCapacity:[jsonDevices count]];
for (NSDiectionary *s in jsonDevices) {
Device *newDevice = [[Device alloc] init];
device.deviceName = [s objectForKey:#"name"];
[retDevices addObject: newDevice];
}
return retDevices;
I then use the AppDelegate class's devices array to populate a tableView. As seen in the cellForRowAtIndexPath method:
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
Device *d = (Device *)[appDelegate.devices objectAtIndex:indexPath.row];
cell.label.text = d.deviceName;
When the tableview is populated initially, it works. But when I scroll through the list, and the cellForRowAtIndexPath is executed again, d.deviceName throws an error because it has gone out of scope.
Can anyone help me understand why? I'm sure it has something to do with an item being released... but... ??
Thanks in advance.
If it is indeed a problem with memory management, answering these questions should lead you to an answer:
Is deviceName declared as a retain or copy property by the Device interface declaration?
Is -deviceName synthesized? If not, how is it implemented?
Is devices declared as a retain property by the app delegate class's interface declaration?
Is devices synthesized? If not, how is it implemented?
Of course, it might not be a problem with memory management. It would help a lot if you were to provide the actual text of the error message and any provided backtrace.

NSKeyedUnarchiver does not call initWithCoder

I've used the following example:
game state singleton cocos2d, initWithEncoder always returns null
Instead of using a file, I use an NSData object i am getting from NSUserDefaults. It is not null, but rather have data in it that I believe is the correctly encoded data and for some reason when I run unarchiveObjectWithData it does not call initWithCoder as I put an NSLog on the first line.
Ideas?
+ (void)loadState {
#synchronized([AppStateManager class]) {
if (!sharedAppStateManager) {
[AppStateManager sharedManager];
}
NSUserDefaults *udefs = [NSUserDefaults standardUserDefaults];
NSData *archivedData = [udefs objectForKey:#"AppState"];
NSLog(#"going to unarchive");
[NSKeyedUnarchiver unarchiveObjectWithData:archivedData];
NSLog(#"unarchive complete");
}
}
- (id)initWithCoder:(NSCoder *)decoder {
NSLog(#"init coder");
self = [super init];
if (self != nil) {
[self setUsername:[decoder decodeObjectWithKey:#"username"]];
}
return self;
}
Solved.
The example posted at the link above initializes the object via "sharedInstance" using the allocWithZone method. If the object exists it returns nil.
the NSKeyedUnarchiver tries to alloc AGAIN via allocWithZone and since the object has already been initialized earlier in that very same method, or sometimes before hand the unarchiver gets a nil instead of an allocated object.
Hope this helps someone.
I don't know why, but after I do this to obtain my NSData of the archive (the contents of which i think is inconsequential):
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSData *encodedConfig = [userDefaults valueForKey:kConfiguration];
When I execute this, it returns nil.
NSArray *configs = [NSKeyedUnarchiver unarchiveObjectWithData:encodedConfig];
But when I execute this, I get the expected, previously archived, array of objects.
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:encodedConfig];
NSArray *configs = [unarchiver decodeObject];
I expect identical behavior from these two approaches. My only response is avoid unarchiveObjectWithData:.
This isn't so much an answer but a bit of additional info I found while trying to work a similar issue out. I guess I am still under rookie status, so this is the only way I could find to contribute to this post.
Anyways...
Thanks so much for banging through this issue...especially over here:
http://www.cocos2d-iphone.org/forum/topic/11327
I was having a problem with a mutable array working using the method you had worked out where it would switch to an immutable array after I unarchived it from the file.
Casting the returned array as a mutable version did not work either.
I end up adding objectsFromArray to my mutable array and this solved my problems.
Worked:
[self.mutableArray addObjectsFromArray:[decoder decodeObjectForKey:#"MutableArray"]];
Neither of these worked:
self.mutableArray = [decoder decodeObjectForKey:#"MutableArray"];
self.mutableArray = (NSMutableArray *)[decoder decodeObjectForKey:#"MutableArray"];