I've followed a few tutorials and I cant seem to adapt them to my needs.
Simply I have a manager objects that returns a NSInvocation to be stored and invoked at a later point in the app.
and when I run the application, my method signature is null and even trying to assign a NSInvocation from a getter is causing a SIGABRT.
#interface Cars : NSObject
+ (NSArray *)all;
#end
cars all method just returns an array "1","2","3","4".
and in my object manager I do this:
- (NSInvocation *) cars_ALL {
NSMethodSignature *ca = [Cars instanceMethodSignatureForSelector:#selector(all)];
NSLog(#"%#", ca);
return [NSInvocation invocationWithMethodSignature:ca];
}
and I call it like this:
NSInvocation *cinv = [myObjectManager cars_ALL];
thats it, im not even up to invoking or assigning the target etc of the invocation.
anything I try just doesn't work out.
Related
I am designing a new application by modernizing code I wrote in the past. This old code uses the class/delegate model and I am trying to transform them to use blocks as callbacks, not the delegate stuff.
What I do is to create a property like
#property (nonatomic, copy) void (^onTouch)(NSInteger index);
That would pass to the object using that class a block where code can be inserted and in this case executed on touch.
But my problem is this. When you use delegates and you have a method on the delegate protocol, Xcode will warn if you use that class and forget to implement the delegate protocols. Is that a way to do that with blocks? Or in other words: is there a way to make Xcode complain if a callback block is not defined by the caller?
I mean this would be the correct:
MyClass *obj = [[MyClass alloc] init];
obj.onTouch = ^(NSInteger *index){ //call back code to be executed };
This would be OK too
MyClass *obj = [[MyClass alloc] init];
obj.onTouch = nil;
but this would generate a message
MyClass *obj = [[MyClass alloc] init];
// no callback block defined.
Is this possible?
If you want to enforce setting a certain parameter, I would include it in the initializer.
MyClass *obj = [[MyClass alloc] initWithBlock:^(NSInteger *index) { /* code*/ }];
Then, in MyClass:
- (id)init {
// This will result in a runtime error if you use the wrong initializer.
NSAssert(NO, #"Use initWithBlock instead.");
}
- (id)initWithBlock(initWithBlock:^(NSInteger *)block) {
self = [super init];
if (self) {
self.onTouch = block;
}
return self;
}
Also note, attempting to execute a NULL block results in a crash, so make sure to do:
if (self.onTouch) { self.onTouch(); }
Wherever you run the block.
First, I strongly recommend defining types to represent your blocks - makes them a lot easier to work with, especially if you need to refactor the parameters.
You can't write code that distinguishes between "I set this property to nil" or "the runtime initialized this property to nil", at least not without some crazy runtime code to check the stack. Only option I can think of would be to use the null object pattern. Before I elaborate, bear in mind that I haven't actually tried to test this, but it should work. Define a block that means 'has no value' and set your property to point to that block on init. Then you can compare to that NullBlock at runtime to identify if someone explicitly set the property to nil (because it would be nil at that point) or gave it a real non-nil value.
Alternatively, if you don't mind manually writing your set accessors, you could have a BOOL that tracks if someone set the property explicitly. Then when you call the block just check if someone actually set the value or not.
#synthesize onTouchBlock=_onTouchBlock;
MyBlock _onTouchBlock;
BOOL _onTouchBlockWasSet;
- (void)setOnTouchBlock:(MyBlock)block {
_onTouchBlockWasSet = YES;
_onTouchBlock = block;
}
I would not recommend passing the value in the initializer because that makes it tied to the creation of that object type. If you wanted to change the block in code based on some condition, you'd be back to square one. Also, it prevents you from using storyboards which create that object.
I have an interface like this:
#interface MacCalculatorAppDelegate:NSObject
<UIApplicationDelegate> {
// ...
UIButton *operatorPressed;
NSString *waitingOperation;
}
And I am initializing waitingOperation variable in my implementation like this:
- (id)init {
if (self = [super init]) {
waitingOperation = #"not set";
}
return self;
}
And I want to reinitialize this variable in a function. This is calculator program and when user clicks on operators button the following function will be invoked:
- (IBAction)operatorPressed:(UIButton *)sender {
if([#"+" isEqual:operand]) {
waitingOperation = #"+";
}
}
But after the check in if statement, my program won't do anything and this happens when I am trying to reinitialize waitingOperation variable.
I am new to objective-c, please help me understand what's wrong here.
Thanks in advance.
There are several things to note here.
waitingOperation=#"not set";
As it stands, this will eventually crash your program. Objective C string literals are autoreleased instances of NSString, which means unless you assign it to a retained property or retain it manually, the memory will be deallocated, leaving a dangling pointer.
-(IBAction) operatorPressed:(UIButton *)sender {
Have you verified that this method is actually being called? You have to assign the IBAction in Interface Builder. Step through it in the debugger or use NSLog to verify that this method is being called.
if([#"+" isEqual:operand])
Where is operand coming from?
waitingOperation=#"+";
Same problem as above, this will get deallocated behind the scenes, leaving you with a dangling pointer.
Also, note that if you know that both variables are NSStrings, using isEqualToString: is faster than using isEqual:.
Finally, this stuff shouldn't be part of your app delegate. This is view controller logic.
If your operand is also a string, then check for isEqualToString instead of isEqual
i have some trouble writing a method in Objective-C to make an object nil. Here is some example :
#interface testA : NSObject
{
NSString *a;
}
#property (nonatomic, retain) NSString *a;
+(testA*)initWithA:(NSString *)aString;
-(void)displayA;
-(void)nillify;
#end
#implementation testA
#synthesize a;
+(testA*)initWithA:(NSString *)aString{
testA *tst=[[testA alloc] init];
tst.a=aString;
return [tst autorelease];
}
-(void)displayA{
NSLog(#"%#",self.a);
}
-(void)nillify{
self=nil;
}
- (void)dealloc {
[a release];
[super dealloc];
}
#end
int main(int argc, char **argv){
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
testA *test=[testA initWithA:#"some test"];
[test displayA];
test=nil;
//[test nillify];
NSLog(#"after setting to nil");
[test displayA];
[pool release];
return 0;
}
Apparently , when I set test object to nil and then call some method on it nothing happens , but if i call nillify instead of directly setting it to nil , displayA method works normally like test object is still there. Is there a workaround for nillify method to function properly ?
Your help is much appreciated !
You can't actually do something like this, because setting 'self' to nil only has any effect within the scope of that method (in your case, 'nilify'). You don't have any actual way to effect the values of pointers located on other parts of the stack or in random places in the heap, for example.
Basically any code that holds a reference to some object is responsible for maintaining and clearing those references itself. If you have some use case where random sections of code may need references to "live" objects of some kind, but where you'd want those object references to go away in response to some external event (maybe a user tracking system or something), you could do something with notifications, but the various modules tracking those "live" objects would still be responsible for listening for notifications and cleaning up references when they received them.
The 'nilify' thing, however, can't possibly work.
You cannot do what you're trying to do. self is just a local reference to an object that actually exists elsewhere. Setting it to nil doesn't mean anything. An object doesn't, in general, own itself, and it certainly doesn't control other objects' references to it. It's up to the owning objects to manage its lifetime.
There are a few things wrong with your code.
First, by convention, class names start with an uppercase letter. Please stick to these naming conventions as it will make it harder for other developers to work with your code (and even confuse you).
Next, your initWithName:... According to the naming conventions, a method with init in its name should be an instance method, not a class method. So either name it newWithName: or turn it into an instance method like this:
-(testA*)initWithA:(NSString *)aString{
self = [super init];
if (!self) return nil;
tst.a=aString;
return self;
}
If you keep it as class method (and name it newWithName:) you should not return a autoreleased object since according to the naming conventions method that start with init... or new... return a retained object. If you do not follow these conventions, the static analyzer will give you "false" warnings and it will become useless for you.
Now for the reason your nillify doesn't work: the self is in fact an argument to a method. Under the hood, your nillify method actually has two arguments that you do not see: the self pointer and the selector pointer. This means, self is actually a variable on the stack. And if you overwrite it, you only overwrite that stack variable but that doesn't influence your test variable which is somewhere else.
As an example, consider a method - (void)foo:(NSString *)bar;. The compiler turns it into the equivalent of the C function (void) foo(id self, SEL _cmd, NSString *bar).
I'm using NSInvocation as follows:
In my init, I'm writing this in my viewDidLoad:
SEL mySelector;
mySelector = #selector(initParsersetId:type:);
NSMethodSignature * sig = nil;
sig = [[self class] instanceMethodSignatureForSelector:mySelector];
myInvocation = nil;
myInvocation = [NSInvocation invocationWithMethodSignature:sig];
[myInvocation setTarget:self];
[myInvocation setSelector:mySelector];
And I'm calling it like this:
Idea *tempIdea = [[Idea alloc]init];
tempIdea = [genericArray objectAtIndex:indexPath.row];
idea.ideaId = tempIdea.ideaId;
[tempIdea release];
NSNumber *_id_ = [NSNumber numberWithInt:idea.ideaId];
[myInvocation setArgument:_id_ atIndex:2]; //CRASHING AT THIS LINE
My application is crashing at the indicated line. Can anybody please help me?
It is not very clear from your codes; however, I see something suspicious. Hopefully, it may provide your some helpful hints.
First, I don't see you retain the instance (auto released from [NSInvocation...). Since the instance from [NSInvocation...] is auto-released, your class level variable myInvocation would not retain it after viewDidLoad event.
Second thing in your codes is that the selector is a kind of customized constructor, beginning with init..... I am not sure if you can invoke the event within the same instance. Another point is that if your init... method to be invoked returns self? It should be.
You may output some messages in your selector event by using NSLog function. All the messages by NSLog will be in your XCode's output console.
I've found the answer but I'm not convinced how. Actually, initially I was writing all the initialisation code in viewDidLoad and simply reusing the NSInvocation object by passing it the different argument since NSInvocation is a mutable object. It didn't work. Then I wrote a method with all the initialisation code inside it and called that method every time I used the NSInvocation object and it worked...
You need to give setArgument: the address of the argument you are passing, and not the argument itself:
[myInvocation setArgument:&_id_ atIndex:2];
NOT
[myInvocation setArgument:_id_ atIndex:2];
Also, are you sure your function takes an NSNumber as first argument?
Alright, so I think I'm doing this the right way. I'm new to objective-C, so I'm not sure about the syntax... I have a set of code that I need to call multiple times, from different files. So I made a new class that has a method in it that I'll call and pass it the values that it needs.
Because I am passing different values I've put them in a dictionary and decided to just pass the dictionary. Here is that code:
NSNumber *testNum = [NSNumber numberWithInt:varMoney];
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
[dictionary setObject:#"OMG, Object 1!!!!" forKey:#"1"];
[dictionary setObject:#"Number two!" forKey:#"2"];
[dictionary setObject:testNum forKey:#"3"];
This code creates a test variable, and then puts it into the dictionary "dictionary." That all works, I have my nice little dictionary. However, now I need to create the class and it's method that will recieve the dictionary, and do something with it.
This is my class header file:
#import <UIKit/UIKit.h>
#interface EndOfTurnObjC : UIView {
}
#end
And this is the implementation file:
#import "EndOfTurnObjC.h"
#implementation EndOfTurnObjC
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// Initialization code
}
return self;
}
- (void)dealloc {
[super dealloc];
}
#end
I haven't created any of the real code, because I'm not sure how to do the passing. I need to create a function (Method?) in the class that will take a Dictionary has a parameter, and then return the dictionary.
I also have no idea how to call such a function because it's in the class. So, the questions are:
1: How do I define the method in the class to accept the dictionary as a parameter (and then perhaps some example code to pull out one of the objects in a dictionary, so I can be sure it works)
2: How do I return the dictionary at the end of the method?
3: How do I call this method, in the class, from another class? (I know it involves making an object of thing class and calling the method of the object... I think, but I'm not sure about the syntax.)
Please include relavent code for the 3 files (header, implementation, and the other class that I call from). Thank you so much, I've been working on this particular problem for a while now.
Apple's The Objective-C Programming Language is a good and pretty concise reference for Objective-C syntax. What you want is just a normal method that takes an NSDictionary as a parameter. So as given in that document:
A message with a single argument affixes a colon (:) to the selector name and puts the argument right after the colon. This construct is called a keyword; a keyword ends with a colon, and an argument follows the colon, as shown in this example:
[myRectangle setWidth:20.0];
So a method call to pass dictionary would look like:
[someObject setAttributes:dictionary];
In the header:
-(NSMutableDictionary *) doSomethingWithDictionary:(NSMutableDictionary *) aDict;
in the implementation:
-(NSMutableDictionary *) doSomethingWithDictionary:(NSMutableDictionary *) aDict{
//do something with the dictionary
return aDict;
}
To call the method:
NSMutableDictionary *returnDict=[EndOfTurnObjC doSomethingWithDictionary:dictionary];
Note that as a matter of good design you wouldn't want to pass a mutable dictionary around like a token. That is asking for trouble. Instead pass static dictionaries and get another dictionary back.
You also shouldn't be passing data to a UIView. Instead, your UIViewController should process the data and then populate the view's UI elements as needed.
if you just want to do stuff to your dictionary u just
-(void) changeMyDictionary:(NSMutableDictionary * ) dictionary_
{
[dictionary_ doStuff];
....
...
}
no need to return the dictionary.