I decided to start learning some Obj-C. And I thought that Wikibooks wikidraw application would be a good place to start (after some very basic "Hello World" programs). I've followed the chapters and now I'm at the end of "WikiDraws view class". So now I'm supposed to be able to compile and run. Of course it dosen't work. I got a lot of errors at first but i have fixed most of them, only 6 remaining. This is one of them:
- (void) mouseDragged:(NSPoint) pt
{
NSPoint np;
np.x = pt.x - _anchor.x;
np.y = pt.y - _anchor.y;
if ( _dragState == 0) {
// dragging of object
[self offsetLocationByX:np.x byY:np.y];
}
else if ( _dragState >= 1 && _dragState < 9 )
{
// dragging a handle
NSRect nb = [self newBoundsFromBounds:[self bounds] forHandle:_dragState withDelta:np];
[self setBounds:nb];
}
}
- (NSRect) newBoundsFromBounds:(NSRect) old forHandle:(int) whichOne withDelta:(NSPoint) p
{
// figure out the desired bounds from the old one, the handle being dragged and the new point.
NSRect nb = old;
switch( whichOne )
{ ..........
So at
NSRect nb = [self newBoundsFromBounds:...
I get an error message, "Invailid initializer" and "WKDShape may not respond to '-newBoundsFromBounds:forHandle:withDelta:"- . What should I do? I'm new to coding but eager to learn.
/Carl-Philip
Assuming you've pasted that code in the order written in your source code and newBoundsFromBounds:forHandle:withDelta: isn't declared (as distinct from being defined) at some earlier point, I think the problem is just that at nb = [self newBoundsFromBounds:... the compiler doesn't yet know what the return type will be. An NSRect is a C-style struct rather than an Objective-C class, so the compiler really does need to know.
As a solution, either put the definition of newBoundsFromBounds:... before mouseDragged:, add it to the #interface in your header file if you want it to be exposed to everyone or declare it internally to the implementation file as a category method. To do the final one, add the following to the top of your .m, assuming your class is called WikiDrawsView:
#interface WikiDrawsView (private)
- (NSRect)newBoundsFromBounds:(NSRect) old
forHandle:(int) whichOne
withDelta:(NSPoint) p;
#end
The 'private' is just a name you get to pick, it has no special meaning. Something like 'private' is often used to signify that you're using a category in a similar way that you might use private class member functions in C++ or a language like that.
The quick way to describe categories is that they patch additional methods onto existing classes at runtime, and they use the #interface [classname] ([category name]) syntax, with no member variable section. I'm sure your tutorial will get to them, Apple's documentation on them is here. This is a common use of categories but not the primary use.
To address the "WKDShape may not respond" warning, make sure you declare -newBoundsFromBounds:forHandle:withDelta: before -mouseDragged:. You can add it to the public interface in "WKDShape.h", or in an anonymous category in "WKDShape.m".
Related
I'm currently trying to learn Objective C and by this way, Oriented Object languages.
I'm declaring variables from a class I've written, but, my functions are way too long, and I'd like to cut that code off.
I do not know how the return works with classes and that's my problem.
Grapejuice *juice;
juice = [[Grapejuice alloc] init];
[juice setName:#"Grape juice"];
[juice setOrderNumber:1000];
[juice setPrice:1.79];
This, is part of a main in which I'm doing this to several objects, how can I do that in a separated function, and still got these informations out of this new function to be re-used later (to be printed for example) ?
Not sure if I'm clear but I've just started learning it yesterday, still hesitating on the basics.
Thanks homies.
If I understand you correctly, I believe what you want is a custom "init" method for your Grapejuice class.
In Grapejuice.h, add:
- (instancetype)initWithName:(NSString *)name orderNumber:(NSInteger)number price:(double)price;
In Grapejuice.m, add:
- (instancetype)initWithName:(NSString *)name orderNumber:(NSInteger)number price:(double)price {
self = [super init];
if (self) {
_name = name;
_orderNumber = number;
_price = price;
}
return self;
}
Then to use that code you do:
Grapejuice *juice = [[Grapejuice alloc] initWithName:#"Grape Juice" orderNumber:1000 price:1.79];
Please note that you may need to adjust the data types for the orderNumber and price parameters. I'm just guessing. Adjust them appropriately based on whatever type you specified for the corresponding properties you have on your Grapejuice class.
I have been doing some research online and have found that using the ObjectiveC package in Objective C you can get a list of all the methods on a class using class_copyMethodList(), and I see you can get the implementation (IMP) of a method using instanceMethodForSelector:. The Apple documentation here has been helpful so far but I'm stuck and not sure what I'm really looking to find.
I want a list of the methods/functions called in a given method's implementation so I can build a call tree.
Any suggestions? Thanks in advance!
This solution is kind of hard way, and will cause a line of code in every method You can also make use of sqlite and save the tracked methods..
MethodTracker.h
#interface MethodTracker : NSObject
#property (nonatomic) NSMutableArray *methodTrackArr;
+ (MethodTracker *)sharedVariables;
#end
MethodTracker.m
#implementation MethodTracker
static id _instance = nil;
+ (MethodTracker *)sharedVariables
{
if (!_instance)
_instance = [[super allocWithZone:nil] init];
return _instance;
}
// optional
- (void)addMethod:(NSString *)stringedMethod
{
// or maybe filter by: -containObject to avoid reoccurance
[self.methodTrackArr addObject:stringedMethod];
NSLog("current called methods: %#", methodTrackArr);
}
#end
and using it like:
OtherClass.m
- (void)voidDidLoad
{
[super viewDidLoad];
[[MethodTracker sharedVariables] addMethod:[NSString stringWithUTF8String:__FUNCTION__]];
// or directly
[[MethodTracker sharedVariables].methodTrackArr addObject:[NSString stringWithUTF8String:__FUNCTION__]];
}
- (void)someOtherMethod
{
// and you need to add this in every method you have (-_-)..
[[MethodTracker sharedVariables] addMethod:[NSString stringWithUTF8String:__FUNCTION__]];
}
i suggest you import that MethodTracker.h inside [ProjectName]-Prefix.pch file.
Sorry, for the double answer, i deleted the other one and i have no idea how did that happen..
Hope this have helped you or at least gave you an idea.. Happy coding,
Cheers!
I think in the runtime track method is possible, but function not.
I have been build a tool DaiMethodTracing for trace all methods activity in single class for some of my need. This is based on objective-c method swizzling. So, there is an idea to do this
List all Classes in your application.
swizze all the methods in each class.
filter the method you want to trace.
finally, you may got the method call path.
Hello all,
I've been working on some enumeration routines in Objective-C that perform object introspection. In particular, I'm fast enumerating an NSSet and making sure that the objects therein belong to class BBBallView (an fairly unfortunate name, I agree) before tweaking their properties and/or calling their methods.
In order to make the parser and compiler happy, however, I end up casting the object to its class on every single line; moreover, in order to access its properties, the object's cast has to be in parentheses, otherwise dot notation won't work. This leads to somewhat messy code:
for (id otherBall in self.gameField.subviews) {
if ([otherBall isKindOfClass:[BBBallView class]]) {
if ( !((BBBallView *)otherBall).isEnlarged ) {
CGRect otherFrame = ((BBBallView *)otherBall).frame;
/* ... */
}
}
}
Is there any way to tell the compiler something like "at this point I know that otherBall is a BBBallView, so stop telling me it doesn't respond to these selectors and properties"? That way, one could just write:
for (id otherBall in self.gameField.subviews) {
if ([otherBall isKindOfClass:[BBBallView class]]) {
if ( !otherBall.isEnlarged ) {
CGRect otherFrame = otherBall.frame;
/* ... */
}
}
}
and so on.
I tried otherBall = (BBBallView *)otherBall but "fast enumeration variables can't be modified in ARC by default". Changing the enumeration variable to __strong id fixes it, but doesn't help the fact that any subsequent line gives out errors such as "property isEnlarged not found on object of type 'const __strong id'", so I'm back to square one.
I'm not even sure why exactly this happens: shouldn't the compiler stay out of the way when an variable is of type id? In any case, the whole ordeal particularly messy in methods that need to perform several calculations on objects' properties, as it quickly becomes unreadable with all those parentheses.
Is there any way around this?
Thanks in advance!
You can either create a local temp with the correct type or just not use dot notation.
local temp
for (UIView *view in self.gameField.subviews) {
if ([view isKindOfClass:[BBBallView class]]) {
BBBallView *ballView = view;
if (!ballView.isEnlarged) {
CGRect otherFrame = ballView.frame;
/* ... */
}
}
}
don't use dot notation
for (id otherBall in self.gameField.subviews) {
if ([otherBall isKindOfClass:[BBBallView class]]) {
if ( ![otherBall isEnlarged]) {
CGRect otherFrame = [otherBall frame];
/* ... */
}
}
}
If I was only doing a couple of things I would be tempted to not use dot notation. If it became awkward to read and there was a lot of accesses then I would consider local temp
I think you're struggling because the logic appears misplaced. The language is fighting you because of your program's structure, not because the language is deficient.
Is the parent type of subviews really appropriate? Or are you violating the Liskov Substitution Principle by stuffing a round object in a square type?
You can also ask if is it really appropriate to examine the internals of BBBallView logic from outside? Can you move the logic into the appropriate class?
I am writing code for the iPad. I have a point structure that I define:
typedef struct __Point32_t
{
int32_t x;
int32_t y;
}Point32_t;
Here is my code to receive a structure back from an objective-C method:
Point32_t ModalityPan = [self ReadPoint];
Here is the method:
-(Point32_t)ReadPoint
{
Point32_t P;
P.x = [self ReadInt];
P.y = [self ReadInt];
return P;
}
The assignment of the return value to the structure creates an error at compile time. The error claims I have an invalid initializer. If I change the assignment to:
Point32_t * ModalityPan = [self ReadPoint];
the error goes away. So I am left wondering what is actually being passed back in Objective-C. I have searched through many posts, some here at SO, and I am under the impression that structures are passed and returned to and from methods in Obj-C without needing to reference the structure (e.g., I am allowed to pass by value).
Can anyone explain what is happening under the hood here? What is coming back, a reference or a structure? and if a structure, why do i need to specify a reference as the type of variable being assigned to?
Well it turns out that the compiler was warning me in a very indirect way that my method was not defined in the #interface and the implementation for the method was below my using it. So the compiler appears to not have been able to figure out what the return type was. It compiles correctly now.
I have a small app that uses cocos2d to run through four "levels" of a game in which each level is exactly the same thing. After the fourth level is run, I want to display an end game scene. The only way I have been able to handle this is by making four methods, one for each level. Gross.
I have run into this situation several times using both cocos2d and only the basic Cocoa framework. So is it possible for me to count how many times a method is called?
Can you just increment an instance variable integer every time your method is called?
I couldn't format the code in a comment, so to expound more:
In your header file, add an integer as a instance variable:
#interface MyObject : NSObject {
UIInteger myCounter;
}
And then in your method, increment it:
#implementation MyObject
- (void)myMethod {
myCounter++;
//Do other method stuff here
if (myCounter>3){
[self showEndGameScene];
}
}
#end
I don't know if your way is the best way to do it, or if mine is, but like Nathaniel said, you would simply define an integer to hold the count in your #interface:
#interface MyClass : NSObject {
int callCount;
}
Then the method can increment this by doing:
- (void) theLevelMethod {
callCount++;
// some code
}
Make sure you initialize the callCount variable to 0 though, in your constructor or the equivalent of viewDidLoad. Then in the code that checks the count you can check:
if (callCount == 4) {
// do something, I guess end scene
}
Then again, I guess you can simply do something like this:
for (int i = 0; i < 4; i++) {
[self theLevelMethod];
}
[self theEndScene];
I don't know how your game logic works, but I guess that would work.
Sorry if I misunderstood your question.