Question about instantiating object - objective-c

I am new to Objective C and Cocoa. Really don't like the syntax as I'm from Java and C#. I'm trying to do something simple and I get the following error:
I import this in using
#import "Defaults.h"
-(void) awakeFromNib{
Defaults *theDefaults = [[Defaults alloc] init];
}
-(IBAction) addPlanets:(id)sender{
[theDefaults setValue:[planetsButton titleOfSelectedItem] forKey:#"planets"];
NSLog([planetsButton titleOfSelectedItem]);
}
The error I get is
Unknown Receiver theDefaults; Did you mean "Defaults"?
Can someone help me on what this is?

theDefaults doesn't exist in the scope of addPlanets:. You need to make it a global or an instance variable, rather than creating it in awakeFromNib and immediately leaking it.

Related

Initializing a constant that's value takes a completionBlock argument in its initializer

I have a property, that in Objective-C I created like this:
self.myProperty = [[MyClass alloc] initWithCompletionBlock:^(MyClass *object) {
dispatch_async(dispatch_get_main_queue(), ^{
[self doSomethingAfterInitialization];
});
}];
And it worked great. Initialization of the MyClass object could create an indeterminate amount of time, so I passed a completionHandler in to it. When it finished, doSomethingAfterInitalization: would handle business.
Now in Swift, I'm trying to create the same object and assign it to a property, with problems.
The property never will change, so it makes sense to me to create it as a Swift constant.
So I'm trying it like this:
let myProperty = MyClass(completionBlock:{ (MyClass) -> (Void) in dispatch_async(dispatch_get_main_queue(), doSomethingAfterInitialization())})
To me that seemed like a direct translation... but the Swift compiler tells me that's not correct, via the error
Use of instance member 'doSomethingAfterInitialization' on type 'MyViewController'; did you mean to use a value of type 'MyViewController' instead?
Well that didn't help much. So instead I tried changing the call to the doSomethingAfterInitialization function to self. doSomethingAfterInitialization(), in which case I see
Value of type '(NSObject) -> () -> TodayWidgetTableViewController' has no member 'doSomethingAfterInitialization'
Any idea how I can fix this? Obviously my initializer is a little weird in the first place, so I'm wondering if this is something that doesn't really translate at all to Swift.

Objective-C : Something that I don't understand with the init method

I was encountering an issue with my code and somebody explained me that it was because I wasn't creating an instance for my property, he told be that I should do that in my init method. What I don't understand is this : I already created my object by doing like this :
TADIgnoringConstraint *ignorer = [TADIgnoringConstraint new];
I know that I could also use [[TADIgnoringConstraint alloc] init] but I see that the init method is already existing, so should I create a new custom initialization method with another name ? In that case, how do I create a init function ? What does this function returns ?
[TADIgnoringConstraint new]
Is exactly the same thing with
[[TADIgnoringConstraint alloc] init]
Which allocates the object in memory and initializes it. When you call init on a allocated object, it runs the init method of the object if declared, if not it runs the init of the superclass which returns the object it self.
Now what #Wain told you was to instantiate your array in your init method. Which is the typical practice in most cases.
You can do something like this:
- (id)init
{
self = [super init];
if (self) {
// Set your properties properly here
// before you actually return the object so they can be ready to use
_someMutableArray = [NSMutableArray array];
}
return self;
}
new is the same as alloc followed by init. In NSObject, new is defined as
+ (id)new
{
return [[self alloc] init];
}
Looking at the other thread, the assumed problem is that you may not be initializing the tockensArray property. If that's true, then you need to do that in the init method of TADIgnoringConstraint, which you say already exists.
What you need in that case would be something like:
self.tockensArray = [NSMutableArray array];
If that's not the actual problem, show how you declare tockensArray and what is currently in your init.
TADIgnoringConstraint *ignorer = [TADIgnoringConstraint new];
That line of code creates a new object of class TADIgnoringConstraint and stores a pointer to that object into a local variable. Because it is a local variable and apparently not stored anywhere else, it will be deleted by ARC as soon as you leave the function or method where this happens.
I strongly recommend using [[TADIgnoringConstraint alloc] init], mostly for the reason that everybody does. Following conventions means that your code is easier to read, and people including yourself don't need to check whether your problems are caused by not following conventions. (You may say: "But new is the same as alloc + init" to which I would reply "your code isn't working. Would you bet $1000 that it is indeed the same?").

ObjectiveC and JavaScriptCore: Will using this method of calling CallBacks cause memory issues?

DISCLAIMER: This is a long post, but could prove very valuable for those grappling with using the new ObjectiveC JavascriptCore framework and doing asynchronous coding between ObjC and JS.
Hi there, I'm super new to Objective C and am integrating a javascript communication library into my iOS app.
Anyway, I've been trying my hand at using the new ObjectiveC JavaScriptCore Framework introduced in iOS7. It's pretty awesome for the most part, though quite poorly documented so far.
It's really strange mixing language conventions, but also kind of liberating in some ways.
I should add that I am of course using ARC, so that helps a lot coming from the Javascript world. But I have a question that's pretty specific around memory use issues when moving between ObjectiveC and the JSContext callBacks. Like if I execute a function in Javascript that then does some asynchronous code, and then calls back to a defined ObjectiveC block, and then that calls a defined JS callback... I just want to make sure I'm doing it right (ie. not leaking memory some place)!
Just to do things proper (because I reference a the class self to call the ObjectiveC callBacks I create a weakSelf so it plays nice with ARC (referenced from question: capturing self strongly in this block is likely to lead to a retain cycle):
__unsafe_unretained typeof(self) weakSelf = self;
Now, say I have a JSContext and add a function to it. I want this function to take a callBack function and call it with "Hello" as an argument as well as pass ANOTHER function as a callBack. ie.
// Add a new JSContext.
JSContext context = [[JSContext alloc] initWithVirtualMachine:[[JSVirtualMachine alloc] init]];
// Add a function to the context. This function takes a callBack function and calls it back with "Hello"
[context evaluateScript: #"var functionA = function(callBack){
var aMessage = "Foo";
callBack(aMessage, function(message){
/* message should say: Foo Bar */
});
}" ];
// Note, if you try to copy this code, you will have to get rid of the returns in the JS script.
Okay, so we have our basic JS side of things. Now to add the ObjectiveC complexity. I'm going to add the first ObjectiveC CallBack block:
context[#"functionB"] = ^(NSString *theMessage, JSValue *theCallBack){
[weakSelf objCFunction:theMessage withCallBack:theCallBack];
};
In the same class all this is happening in I also have the method definition. This is the place that causes the most concern to me:
-(void)objCFunction:(NSString *)message withCallBack:(JSValue *)callBack
{
NSString *concatenatedString = [NSString stringWithFormat:#"%#%#", message, #"Bar"];
[callBack callWithArguments:#[concatenatedString]];
}
So when I call:
[context evaluateScript: #"functionA(functionB);" ];
It should pass through the chain, and it does exactly what I expect it to do.
My main concern is that I hope I'm not somehow capturing a JSValue somewhere along this chain that is then leaking out.
Any help in helping me understand how ARC/the JSMachine would manage this approach to calling callBacks fluidly between Objective C and Javascript, would be super valuable!
Also, I hope this question helps others out there who are experimenting with this framework.
Thanks!
The problem with retain cycles occurs when you have two objects, each of which retains part of another. It's not specific to JavascriptCore. It's not even specific to blocks although blocks make the problem much easier to blunder into.
E.g.
#interface ObjcClass : NSObject
#property (strong,nonatomic) JSValue *badProp;
- (void) makeEvilRetainWithContext:(JSContext *) context;
#end
- (void) makeEvilRetainWithContext:(JSContext *) context{
context[#"aFunc"]=^(JSValue *jsValue){
self.badProp=jsValue;
};
}
The self.context[#"aFunc"] now retains the ObjcClass object because self.badProp is now inside the function obj inside the context created by assigning the block to #"aFunc". Likewise, the context is retained because one of its own strongly retained values is retained in self.badProp.
Really, the best way to avoid all this is just to not try and store JSValue in objective-c objects ever. There really doesn't seem to be a need to do so e.g.
#property (strong,nonatomic) NSString *goodProp;
- (void) makeGoodFunc:(JSContext *) context;
#end
- (void) makeGoodFunc:(JSContext *) context{
context[#"aFunc"]=^(JSValue *jsValue){
self.goodProp=[JSValue toString];
};
}
You code isn't a problem because simply passing a JSValue (even a function) through a method won't retain it.
Another way to think of it might be: After, objCFunction:withCallBack: executes, would there be anyway for the object represented by self to access the JSValue passed as callBack? If not, then no retain cycle.
Check out the WWDC introduction "Integrating JavaScript into Native Apps" session on Apple's developer network: https://developer.apple.com/wwdc/videos/?id=615 - it contains a section on Blocks and avoiding capturing JSValue and JSContext
In your sample code above, all the JSValues are passed as arguments (the way Apple recommends) so the references only exist whilst the code is executed (no JSValue objects are captured).

ARC issue with CorePlot

I installed everything according to README file and imported all necessary libraries. Still, when implementing this method:
- (CPTLayer *)dataLabelForPlot:(CPTPlot *)plot recordIndex:(NSUInteger)index {
CPTMutableTextStyle *labelText = nil;
labelText= [[CPTMutableTextStyle alloc] init];
labelText.color = [CPTColor grayColor];
return [[CPTTextLayer alloc] initWithText:#"Test" style:labelText];
}
I receive errors:
ARC Semantic issue - Receiver 'CPTTextLayer' for class message is a forward declaration
and
ARC Semantic issue - Receiver 'CPTTextLayer' for instance message is a forward declaration
I read in many posts, that this is the fault of missing Quartz library, though I have it imported in the project and included in the class: #import <QuartzCore/QuartzCore.h>.
When I return nil instead of this, everything works, but hey, I need those data labels to work!
Anybody knows how to make it work?
Normally forward class error comes when that particular class is not imported in the current class and an #class is declared in .h file. If #class is also not present, it normally gives an unknown type error. So in this case as mentioned in comments, it is clear that the import statement for CPTTextLayer is missing.
I think that you forget to import CPTTextLayer.h on your code

Crash in OS X Core Data Utility Tutorial

I'm trying to follow Apple's Core Data utility Tutorial. It was all going nicely, until...
The tutorial uses a custom sub-class of NSManagedObject, called 'Run'. Run.h looks like this:
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface Run : NSManagedObject {
NSInteger processID;
}
#property (retain) NSDate *date;
#property (retain) NSDate *primitiveDate;
#property NSInteger processID;
#end
Now, in Run.m we have an accessor method for the processID variable:
- (void)setProcessID:(int)newProcessID {
[self willChangeValueForKey:#"processID"];
processID = newProcessID;
[self didChangeValueForKey:#"processID"];
}
In main.m, we use functions to set up a managed object model and context, instantiate an entity called run, and add it to the context. We then get the current NSprocessInfo, in preparation for setting the processID of the run object.
NSManagedObjectContext *moc = managedObjectContext();
NSEntityDescription *runEntity = [[mom entitiesByName] objectForKey:#"Run"];
Run *run = [[Run alloc] initWithEntity:runEntity insertIntoManagedObjectContext:moc];
NSProcessInfo *processInfo = [NSProcessInfo processInfo];
Next, we try to call the accessor method defined in Run.m to set the value of processID:
[run setProcessID:[processInfo processIdentifier]];
And that's where it's crashing. The object run seems to exist (I can see it in the debugger), so I don't think I'm messaging nil; on the other hand, it doesn't look like the setProcessID: message is actually being received. I'm obviously still learning this stuff (that's what tutorials are for, right?), and I'm probably doing something really stupid. However, any help or suggestions would be gratefully received!
===MORE INFORMATION===
Following up on Jeremy's suggestions:
The processID attribute in the model is set up like this:
NSAttributeDescription *idAttribute = [[NSAttributeDescription alloc]init];
[idAttribute setName:#"processID"];
[idAttribute setAttributeType:NSInteger32AttributeType];
[idAttribute setOptional:NO];
[idAttribute setDefaultValue:[NSNumber numberWithInteger:-1]];
which seems a little odd; we are defining it as a scalar type, and then giving it an NSNumber object as its default value. In the associated class, Run, processID is defined as an NSInteger. Still, this should be OK - it's all copied directly from the tutorial.
It seems to me that the problem is probably in there somewhere. By the way, the getter method for processID is defined like this:
- (int)processID {
[self willAccessValueForKey:#"processID"];
NSInteger pid = processID;
[self didAccessValueForKey:#"processID"];
return pid;
}
and this method works fine; it accesses and unpacks the default int value of processID (-1).
Thanks for the help so far!
If you are getting EXC_BAD_ACCESS on
[run setProcessID:[processInfo processIdentifier]];
it's almost certainly due to one of the pointers no longer pointing to a real object. Either run has been dealloc'd or processInfo has been dealloc'd. This assumes that the line is not the next line of code after
NSProcessInfo *processInfo = [NSProcessInfo processInfo];
If it is, then both objects should be valid, so you are probably looking at something wrong with
[self willChangeValueForKey:#"processID"];
or
[self didChangeValueForKey:#"processID"];
if you have any objects observing that key, it's possible they have gone stale somehow.
This did not solve my problem with willAccessValueForKey but it solved a mystery. I subclassed an entity but I forgot to set the custom class in the model. The custom class worked until I wrote a method to send back a string which was a concatenation of some of the properties. The method was nearly identical to another method that was in another custom NSManagedObject class. I could not figure out why the one class worked and the other didn't. Once I set the custom class in the model they both worked.