how to call a method from a class in another class - objective-c

I'm working to a new app for mac osx where i'm using a drag and drop system to let the user to input some files [this part works well] and i have a tabelView where i would like to display the paths of files inputed.
I have the next method in tabelViewController.m:
-(void)add{
NSLog(#"da");
[list addObject:[[Source alloc] init]];
[tableView reloadData];
}
In the DropView.m i included the tabelViewController.h and i'm trying to call the add method but it does nothing:
#import "TableViewController.h"
.....
- (void)concludeDragOperation:(id<NSDraggingInfo>)sender{
[self setNeedsDisplay:YES];
TableViewController *tvc;
[tvc add];
}
Can someone to figure out why it doesn't do anything ?
Edit1:
Ok after I fallow the answers, my concludeDragOperation method looks like this:
- (void)concludeDragOperation:(id<NSDraggingInfo>)sender{
[self setNeedsDisplay:YES];
TableViewController *tvc = [[TableViewController alloc] init];
[tvc add];
[tvc rD];
}
rD is a method from tableViewController which contain the reloadData method.
But it doesn't want to work it don't reload the table view.
Any ideea ???

tvc needs to point to an actual object. [[tvc alloc] init]
Otherwise you are simply calling add on nil. This doesn't cause your program to crash as you might expect in other languages. Try it out and see what happens.

it seems as if you missed a great chunk regarding how OOP and Objective-C work (seriously, no offense there).
What link is there between DropView.m and tableViewController.h do you have?
By typing TableViewController *tvc; all you are doing is creating a pointer. You are neither creating an object nor pointing to an object, you have just simply created a pointer that can eventually point to an object in memory of type tableViewController.
Solution:
What you will need to do, is to somehow create a link between the two classes. For instance, you could create a custom delegate method for DropView that could communicate with any class who uses that custom DropViewDelegate methods. So, you could create a delegate method that tells objects that follow that delegate protocol that you just concluded a drag operation. A tutorial how to do so can be found at my blog [it's a permalink].
I am happy to post code, or you can read it on my blog. Good Luck.

Related

Cocoa Outlets acting wierd, won't recognize selector

I'm getting some weird behavior, I Set a Label in Interface Builder, then I connect the label to a file as an Referencing Outlet.
#property (weak) IBOutlet NSTextField *TitleLabel;
When I access that label in the file (cell.TitleLabel.stringValue = title) and run the application, it doesn't recognize it.I get this:
-[NSApplication TitleLabel]: unrecognized selector sent to instance 0x608000101680
The weird thing is that it doesn't always do this, sometimes it works and displays correctly, other times it doesn't.
I've just started messing with IB so I'm probably missing something. Any help?
Is the property really on your NSApplication subclass? or is it on you application delegate class? It's not impossible for it to be on the application object, but it would be a pretty uncommon (and arguably ill-advised) pattern.
In short, I suspect you're probably connecting it to the wrong object.
EDIT: Ah. I see. You're trying to access things via the topLevelObjects array, but in practice, you can't count on the order of topLevelObjects. What you need to rely on the owner's outlets getting populated, but you're passing nil for the owner. topLevelObjects only exists to give the caller "ownership" (in the reference counting sense) of the top level objects in the xib for memory-mangement purposes, it's not really meant to be "used" directly like you're doing here. (In fairness, I can imagine situations where you might need to introspect that array, but this hardly rises to that level.)
The canonical way to do this would be to use an NSViewController subclass as the owner. In Xcode, if you add a subclass of NSViewController to your project, it will give you the option to create a xib file at the same time that will have everything hooked up. Then you just initialize the NSViewController subclass at runtime and the view outlet property of that class will be filled with the root view. You can obviously add more outlets and plug in whatever you like.
This post appears to cover the basics, if your looking for more details. Apple's docs on xib files and how they work are here.
The problem was that the View would sometimes get assigned to NSApplication. I'm not sure if the way that I am initiating the view is the common way of doing it but the problem was within this block of code:
NSArray * views;
[[NSBundle mainBundle] loadNibNamed:#"CollapseClickViewController" owner:nil topLevelObjects:&views];
CollapseClickCell * cell = [[CollapseClickCell alloc] initWithFrame:CGRectMake(0,0,320,50)];
cell = [views objectAtIndex:0];
the problem was that [views objectAtIndex:0] would sometimes return NSApplication. To fix it I just checked the class against itself and returned that object via:
-(CollapseClickCell*)assignCell:(CollapseClickCell*)cell withArray:(NSArray*)array{
for ( int i = 0; i< [array count]; i++) {
if ([[array objectAtIndex:i] class] == [CollapseClickCell class]) {
return [array objectAtIndex:i];
}
}
return nil;
}
I then assign that to the object:
cell = [cell assignCell:cell withArray:views];
It may not be the conventional way of doing it but it works. If there is a better technique or a more common approach please enlighten me! :)

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.

Delegate issues using GameKitHelper - cocos2d

I'm probably over-thinking this, but I've been stuck on it a while, so I figured I'd reach out for some advice/help.
I'm using GameKitHelper (http://www.learn-cocos2d.com/tag/gamekithelper/), thus far, it's been pretty helpful. So, I have the helper initialized on in my "MainMenu" with the protocol implemented, etc:
#interface MainMenu : CCLayer <GameKitHelperProtocol> {
...
GameKitHelper *gkHelper;
}
In the main menu code, I have this:
gkHelper = [GameKitHelper sharedGameKitHelper];
gkHelper.delegate = self;
[gkHelper authenticateLocalPlayer];
Seems pretty strait forward. In fact, it works, exactly as I expect it to. I have the methods it's looking to be in place there (even though most don't have code associated with them (yet?)). My issue is when I actually want to start my game. So, I'm using the onMatchFound() to start the game, which basically works:
-(void) onMatchFound:(GKMatch*)match
{
[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:1.2f scene: [[MultiplayerLoading initWithData:Multiplayer withMultiplayerType:gameTypeToPlay andInitiator:false] scene]]];
}
My issue is when I'm attempting to play the game, the receive delete method fires in the MainMenu NOT the game class, so things aren't being calculated properly.
Is there a way to pass the control to the game layer from the main menu when the onMatchFound fires?
Hopefully this gives enough info, let me know if not.
Thanks everyone!
There's two ways you can make this work. One way is to have a global Singleton class as the GameKitHelper delegate. You can then relay messages via this Singleton class.
Or simply assign the new scene as the GameKitHelper delegate:
-(void) onMatchFound:(GKMatch*)match
{
CCScene* newScene = [MyNewScene scene];
[GameKitHelper sharedGameKitHelper].delegate = newScene;
[[CCDirector sharedDirector] replaceScene:newScene];
}
Also, there seems to be something wrong with how you create the new scene:
[[MultiplayerLoading initWithData:Multiplayer
withMultiplayerType:gameTypeToPlay
andInitiator:false] scene];
It appears you are first calling the init method, then the class method scene which allocates the instance (see the scene implementation). It looks to me like it should rather be:
[[[MultiplayerLoading alloc] initWithData:Multiplayer
withMultiplayerType:gameTypeToPlay
andInitiator:false] autorelease];
Btw, the Cocoa Coding Guidelines recommend not to "link" method parameters with the "and" keyword and using "with" more than once is also quite odd. Cleaned up it should rather be:
[[[MultiplayerLoading alloc] initWithData:Multiplayer
multiplayerType:gameTypeToPlay
initiator:false] autorelease];
Excuse me for being picky. :)
Could this be because your MainMenu is set as the delegate in your GameKitHelper? I'd try setting the delegate to the game inside onMatchFound. Give that a try.

Custom subview gives memory leak when analyzed

I am trying to create my own custom subview for an app. The view is a subclass of UIView and contains a couple of UIButtons and a UITextField. The code actually builds and runs without problems, but when I do an "Analyze" of the code it gives me 4 potential memory leaks. I will be including this subview in a larger project so I want to nip any errors here before adding it to the bigger project. Here's the code where one of the leaks occurs:
- (void)viewDidLoad
{
[super viewDidLoad];
self.nameView.delegate = self;
[self.nameView.newName resignFirstResponder]; // this is line 60
[self.nameView setHidden:YES];
[self.nameView setNeedsDisplay];
}
The error it gives me is:"Potential leak of an object created on line 60"
Then if I click on that error is says: "Object allocated on line 60 is not referenced later in this execution path and has a retain count of +1, object leaked"
Thanks in advance for any help you can give me.
Gil
CocoaFu, thanks for the help - I am new to the site and I will try to give the proper feedback. As far as this problem goes I should have included a bit more information.
nameView is the name of my custom view
newName is the name of a UITextField in the view.
I will try then suggestions here and let you know if they work. Thanks again. This is a great site!
[self.nameView.newName resignFirstResponder];
is the same as:
[[[self nameView] newName] resignFirstResponder];
which means that newName is a method and methods that begin with new or copy are expected to return a retained instance. I suspect that newName does not do that but the rules say it does. The solution is to follow Objective-C naming rules: change the name newName.
Not, you don't say but perhaps newName is a property. Well, #synthesize creates accessor methods newName and setNetName.

Cocoa without Interface Builder, initialize an instance of app controller?

I don't plan to write applications without IB, I'm just in the process of trying to learn more about programming.
How can I get a single instance of my AppController class at startup? (It's normally loaded from the nib.) And can you clear up the use of +initialize and -init? If I understand, +initialize is called on all classes at startup. How can I use this to create an instance of my AppController with instance variables that make up my interface?
Hope that makes sense, and thanks for any help.
+initalize is sent to a class the first time it or one of its subclasses receives a message for the first time. So, when you do:
instance = [[[YourClass alloc] init] autorelease];
That alloc message triggers initialize.
If you do the same thing with a subclass:
instance = [[[SubclassOfYourClass alloc] init] autorelease];
That alloc message will trigger +[YourClass initialize] the same way the other one did (prior to also triggering +[SubclassOfYourClass initialize]. But only one of these will do it—each class's initialize never gets called more than once. (Unless you call it yourself with [super initialize] or [SomeClass initialize]—so don't do that, because the method won't be expecting it.)
-init, on the other hand, initializes a new instance. In the expression [[YourClass alloc] init], you are personally sending the message directly to the instance. You may also call it indirectly, through another initializer ([[YourClass alloc] initWithSomethingElse:bar]) or a convenience factory ([YourClass instance]).
Unlike initialize, you should always send init (or another initializer, if appropriate) to your superclass. Most init methods look roughly like this:
- (id) init {
if ((self = [super init])) {
framistan = [[Framistan alloc] init];
}
return self;
}
Details differ (this method or the superclass's or both may take arguments, and some people prefer self = [super init] on its own line, and Wil Shipley doesn't assign to self at all), but the basic idea is the same: call [super init[WithSomething:…]], make sure it didn't return nil, set up the instance if it didn't, and return whatever the superclass returned.
This implies that you can return nil from init, and indeed you can. If you do this, you should [self release], so that you don't leak the failed object. (For detecting invalid argument values, an alternative is NSParameterAssert, which throws an exception if the assertion fails. The relative merits of each are beyond the scope of this question.)
How can I use this to create an instance of my AppController with instance variables that make up my interface?
The best way is to do it all in main:
int main(int argc, char **argv) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
AppController *controller = [[[AppController alloc] init] autorelease];
[[NSApplication sharedApplication] setDelegate:controller]; //Assuming you want it as your app delegate, which is likely
int status = NSApplicationMain(argc, argv);
[pool drain];
return status;
}
You'll do any other set-up in your application delegate methods in AppController.
You already know this, but for anyone else who reads this: Nibs are your friend. Interface Builder is your friend. Don't fight the framework—work with it, and build your interface graphically, and your application will be better for it.
Another solution to the problem of launching an app without a nib.
Instead of allocing your own controller, just use the extra parameters in the NSApplicationMain() method:
int retVal = NSApplicationMain(argc, argv, #"UIApplication", #"MyAppDelegate");
This takes care of all the proper linking one would need.
Then, the only other thing you'd need to remember is to make your own window and set it to visible.
A set of NIBs seem to be an unsatisfactory answer, even when represented in XML (as a XIB), because there's no easy way to compare or merge them with any standard subversion or SCM-style tool. The encoded information is fragile and not intended to be edited by mere humans. How would changes be represented by a GUI? Would I step through each attribute of each control and visually check them?
If the app's behavior is written in code, however, there is a chance that I can figure out what's going in, even if I have to keep lots of details close at hand at the same time.
A proposed solution: use a top-level NIB that the main architect coded up, but then code the rest of the app explicitly.
Anybody got a better idea?