I'm having a bit of a nightmare trying to implement the ability to have two players playing against each other on my iPhone app through Game Center.
I am simply trying to access a function within GameCenterManager.m from a different .m file that I have. In my racetohundredViewController.h file I have:
#import <UIKit/UIKit.h>
#import "startPage.h"
#import "GameCenterManager.h"
#import <GameKit/GameKit.h>
#interface racetohundredViewController : UIViewController <UIActionSheetDelegate, GKLeaderboardViewControllerDelegate, GameCenterManagerDelegate>
{
GameCenterManager *gcManager;
BOOL gameIsMultiplayer;
double randomHostNumber;
}
#property (retain, nonatomic) GameCenterManager *gcManager;
in my corresponding .m file I have:
#interface racetohundredViewController ()
#end
#implementation racetohundredViewController
#synthesize gcManager;
- (void)generateAndSendHostNumber;
{
NSLog(#"Generate and send host number");
randomHostNumber = arc4random();
NSString *randomNumberString = [NSString stringWithFormat: #"$Host:%f", randomHostNumber];
NSLog(#"the random number string is: %#", randomNumberString);
[self.gcManager testString];
[self.gcManager sendStringToAllPeers:randomNumberString reliable: YES];
}
- (void)viewDidLoad
{
[self generateAndSendHostNumber];
}
It's the [self.gcManager testString]; and [self.gcManager sendStringToAllPeers:randomNumberString reliable: YES]; that are not being called. They were before, I have clearly messed it up somehow. I can see the NSLog for the random number string.
In my GameCenterManager.h file I have (including some bits unrelated to this problem):
#import <Foundation/Foundation.h>
#import <GameKit/GameKit.h>
#class GKLeaderboard, GKAchievement, GKPlayer;
#protocol GameCenterManagerDelegate <NSObject>
#optional
- (void) processGameCenterAuthentication: (NSError*) error;
- (void) scoreReported: (NSError*) error;
- (void) reloadScoresComplete: (GKLeaderboard*) leaderBoard error: (NSError*) error;
- (void) achievementSubmitted: (GKAchievement*) ach error:(NSError*) error;
- (void) achievementResetResult: (NSError*) error;
- (void) mappedPlayerIDToPlayer: (GKPlayer*) player error: (NSError*) error;
- (void) receivedData:(NSDictionary *)dataDictionary;
#end
#interface GameCenterManager : NSObject <GameCenterManagerDelegate>
{
id <GameCenterManagerDelegate, NSObject> delegate;
NSMutableDictionary* earnedAchievementCache;
id matchOrSession;
}
//This property must be atomic to ensure that the cache is always in a viable state...
#property (retain) NSMutableDictionary* earnedAchievementCache;
#property (nonatomic, strong) id <GameCenterManagerDelegate, NSObject> delegate;
#property(nonatomic, strong) id matchOrSession;
+ (BOOL) isGameCenterAvailable;
- (void) authenticateLocalUser;
- (void)sendStringToAllPeers:(NSString *)dataString reliable:(BOOL)reliable;
- (void)sendString:(NSString *)dataString toPeers:(id)peers reliable: (BOOL)reliable;
-(void)testString;
and finally a cut down version of the .m file for GameCenterManager:
#import "GameCenterManager.h"
#import <GameKit/GameKit.h>
#implementation GameCenterManager
#synthesize earnedAchievementCache;
#synthesize delegate;
#synthesize matchOrSession;
-(void)testString
{
NSLog(#"THIS IS A TEST");
}
I could post code about sendString too but the principle is that even with the basic testString function it is not calling it.
Am I missing something very obvious here? It seems when I step through the code it will highlight the function in the .h file of GameCenterManager, but it won't then display the NSLog as I request.
My best guess would be that self.gcManager is nil. Where do you instantiate your GameCenterManager?
Related
I would like to set an text in the text field in another class and get it from another class. This is something what I want, but it does not work. Can you please help me. Thank you!
aaa.h
#import <Cocoa/Cocoa.h>
#interface aaa : NSImageView {
IBOutlet NSTextField *message;
}
#property (nonatomic, retain) IBOutlet NSTextField *message;
#end
aaa.m
#import "aaa.h"
#import "bbb.h"
#implementation aaa
#synthesize message;
- (void)awakeFromNib {
// [message setStringValue:#"ok, this works!"]; //but i don't want it from here
[self hello];
}
#end
bbb.h
#import <Foundation/Foundation.h>
#interface NSObject (bbb)
- (void)hello;
#end
bbb.m
#import "bbb.h"
#import "aaa.h"
#implementation NSObject (bbb)
- (void)hello {
aaa *obj = [[[aaa alloc] init] autorelease];
[obj.message setStringValue:#"This doesn't work :("]; // set text here, dont work.
NSLog(#"TEST: %#", [obj.message stringValue]);
}
#end
You are using category, so first thing it is used for extending the functionality of existing class. So you cannot set textfield value inside category. But else you can add some functonality after extracting the value. So you have to pass the value inside the category first. Try like this below:
- (void)awakeFromNib {
NSString *resultString=[self hello:#"This doesn't work :("];
[message setStringValue:resultString];
}
#end
#interface NSObject (bbb)
- (NSString*)hello:(NSString*)yourString;
#end
#implementation NSObject (bbb)
- (NSString*)hello:(NSString*)yourString {
return yourString;
}
#end
I have looked at the documentation yet I still haven't successfully implemented a CollectionView. Here is what I have.
My KVO/KVC compliant NSMutableArray.
#import <Foundation/Foundation.h>
#import "ProjectModel.h"
#interface KVOMutableArray : NSMutableArray
#property NSMutableArray* projectModelArray;
- (id)init;
- (void)insertObject:(ProjectModel *)p inProjectModelArrayAtIndex:(NSUInteger)index;
- (void)removeObjectFromProjectModelArrayAtIndex:(NSUInteger)index;
- (void)setProjectModelArray:(NSMutableArray *)a;
- (NSArray*)projectModelArray;
#end
ProjectModel.h file:
#import <Foundation/Foundation.h>
#interface ProjectModel : NSObject {
NSString *applicationName;
NSString *projectPath;
NSImage *image;
}
#property(retain, readwrite) NSImage *image;
#property(retain, readwrite) NSString *applicationName;
#property(retain, readwrite) NSString *projectPath;
#end
ProjectModel.m:
#import "ProjectModel.h"
#implementation ProjectModel
#synthesize image;
#synthesize projectPath;
#synthesize applicationName;
- (id)init {
self = [super init];
image = [NSImage imageNamed:#"xcodeproject.png"];
return self;
}
#end
I also put #property KVOMutableArray *projectsManager; in my AppDelegate.h file and
projectsManager = [[KVOMutableArray alloc] init];
ProjectModel *pm1 = [[ProjectModel alloc] init];
pm1.projectPath = #"path here";
pm1.applicationName = #"Crittercism Example App";
[projectsManager addObject: pm1];
in my awakeFromNib method.
I get the following exception and then it terminates:
[<NSCollectionViewItem 0x1001c2eb0> addObserver:<NSAutounbinderObservance 0x1001e2a20> forKeyPath:#"representedObject.applicationName" options:0x0 context:0x103111690] was sent to an object that is not KVC-compliant for the "representedObject" property.
Not sure what is the problem. Any help is appreciated I know I've written a lot here.
Edit--
The problem seems to be that it can't find representObject.image or any of the other properties for that matter. How can I fix this?
It worked after I implemented these methods (turns out the documentation lied about only needing the 4 methods they suggested there):
#import <Foundation/Foundation.h>
#import "ProjectModel.h"
#interface KVOMutableArray : NSMutableArray {
NSMutableArray *projectModelArray;
}
#property (readonly, copy) NSMutableArray* projectModelArray;
- (id)init;
- (void)insertObject:(ProjectModel *)p;
- (void)insertObject:(id)p inProjectModelArrayAtIndex:(NSUInteger )index;
- (void)removeObjectFromProjectModelArrayAtIndex:(NSUInteger)index;
- (void)setProjectModelArray:(NSMutableArray *)array;
- (NSUInteger)countOfProjectModelArray;
- (id)objectInProjectModelArrayAtIndex:(NSUInteger)index;
- (void)insertProjectModelArray:(NSArray *)array atIndexes:(NSIndexSet *) indexes;
- (NSArray *)projectModelArrayAtIndexes:(NSIndexSet *)indexes;
- (NSArray*)projectModelArray;
- (void)removeProjectModelArrayAtIndexes:(NSIndexSet *)indexes;
- (NSUInteger)count;
- (void)insertObject:(id)object atIndex:(NSUInteger)index;
#end
Set the mode of your array controller Class and the class name to ProjectModel
I have defined a protocol in a separate file (myProtocol.h). Here is the code for it:
#import <Foundation/Foundation.h>
#protocol myProtocol <NSObject>
-(void) loadDataComplete;
#end
Now I want to call this method so I have done the following code:
firstViewController.h:
#import "myProtocol.h"
#interface firstViewController : UIViewController{
id <myProtocol> delegate;
}
#property (retain) id delegate;
-(void) mymethod;
firstViewController.m
#implementation firstViewController
#synthesize delegate;
- (void)viewDidLoad {
[self mymethod];
}
-(void) mymethod {
//some code here...
[delegate loadDataComplete];
}
I have another file where the protocol is also utilized:
secondViewController.h:
#import "myProtocol.h"
#interface secondViewController : UIViewController<myProtocol>{
}
secondViewController.m:
-(void) loadDataComplete{
NSLog(#"loadDataComplete called");
}
but my secondViewController is not calling the protocol methad. Why is it so? Any suggestion will be appreciated.
First, as #Abizern suggested, try to reformat your code a little bit. Use capital letter for classes. Said this here the solution for your answer.
This is the protocol. I would name it like FirstViewControllerDelegate since the class that implements the object is a delegate for FirstViewController.
#import <Foundation/Foundation.h>
#protocol MyProtocol <NSObject>
- (void)doSomething;
#end
This is SecondViewController.
#import <UIKit/UIKit.h>
#import "MyProtocol.h"
#interface SecondViewController : UIViewController <MyProtocol>
#end
#implementation SecondViewController
// other code here...
- (void)doSomething
{
NSLog(#"Hello FirstViewController");
}
#end
This is FirstViewController.
#import <UIKit/UIKit.h>
#interface FirstViewController : UIViewController
// it coud be better to declare these properties within a class extension but for the sake of simplicity you could leave here
// the important thing is to not declare the delegate prop with a strong/retain property but with a weak/assign one, otherwise you can create cycle
#property (nonatomic, strong) SecondViewController* childController;
#property (nonatomic, weak) id<MyProtocol> delegate;
#end
#implementation FirstViewController
// other code here...
- (void)viewDidLoad
{
[super viewDidLoad];
self.childController = [[SecondViewController alloc] init];
self.delegate = self.childController; // here the central point
// be sure your delegate (SecondViewController) responds to doSomething method
if(![self.delegate respondsToSelector:#selector(doSomething)]) {
NSLog(#"delegate cannot respond");
} else {
NSLog(#"delegate can respond");
[self.delegate doSomething];
}
}
#end
For the sake of completeness, be sure to understand the delegate pattern means. Apple doc is your friend. You could take a look at the-basics-of-protocols-and-delegates to have a basic intro on the argument. Furthermore, SO search allows you to find a lot of answers on the topic.
Hope that helps.
this is a follow-up question to my last one here: iOS: Initialise object at start of application for all controllers to use .
I have set my application up as follows (ignore the DB Prefix):
DBFactoryClass // Built a DataManaging Object for later use in the app
DBDataModel // Is created by the factory, holds all data & access methods
DBViewControllerA // Will show some of the data that DBDataModel holds
moreViewControllers that will need access to the same DBDataModel Object
i will go step by step through the application, and will then in the end post the error message i get when building.
AppDelegate.h
#import "DBFactoryClass.h"
AppDelegate.m
- (BOOL)...didFinishLaunching...
{
DBFactoryClass *FACTORY = [[DBFactoryClass alloc ]init ];
return YES;
}
DBFactoryClass.h
#import <Foundation/Foundation.h>
#import "DBDataModel.h"
#interface DBFactoryClass : NSObject
#property (strong) DBDataModel *DATAMODEL;
#end
DBFactoryClass.m
#import "DBFactoryClass.h"
#implementation DBFactoryClass
#synthesize DATAMODEL;
-(id)init{
self = [super init];
[self setDATAMODEL:[[DBDataModel alloc]init ]];
return self;
}
#end
ViewControllerA.h
#import <UIKit/UIKit.h>
#import "DBDataModel.h"
#class DBDataModel;
#interface todayViewController : UIViewController
#property (strong)DBDataModel *DATAMODEL;
#property (weak, nonatomic) IBOutlet UILabel *testLabel;
#end
ViewControllerA.m
#import "todayViewController.h"
#implementation todayViewController
#synthesize testLabel;
#synthesize DATAMODEL;
- (void)viewDidLoad
{
todaySpentLabel.text = [[DATAMODEL test]stringValue];
}
#end
DBDataModel.h
#import <Foundation/Foundation.h>
#interface DBDataModel : NSObject
#property (nonatomic, retain) NSNumber* test;
#end
DBDataModel.m
#import "DBDataModel.h"
#implementation DBDataModel
#synthesize test;
-(id)init{
test = [[NSNumber alloc]initWithInt:4];
return self;
}
#end
when i build it, i get the following error: EXC_BAD_ACCESS in this line:
#synthesize DATAMODEL;
of DBFactoryClass.m
What #synthesize does is to automatically generate implementations of the accessors for a property. EXC_BAD_ACCESS there means that you're accessing garbage when one of the accessors is executed.
That's probably happening here:
[self setDATAMODEL:[[DBDataModel alloc]init ]];
Make sure that DBDataModel's implementation of init actually returns a legitimate object.
As far as I can tell, your DBFactoryClass class is never stored anywhere, and therefore released right after the allocation if you use ARC (Since you use the strong keyword I assumed you do).
- (BOOL)...didFinishLaunching... {
DBFactoryClass *FACTORY = [[DBFactoryClass alloc ]init ];
// If you use ARC this might be released right afterwards
return YES;
}
If you want the factory to be a singleton, use something like this
+ (id)sharedInstance {
static dispatch_once_t once;
static MyFoo *instance;
dispatch_once(&once, ^{
instance = [[self alloc] init];
});
return instance;
}
i've got own delegate for my own class.
MainMenuViewDelegate
#import <Foundation/Foundation.h>
#class MainMenuView;
#protocol MainMenuViewDelegate <NSObject>
-(void) mainMenuViewLibrary:(MainMenuView*)controller withString:(NSString*)string;
#end
MainMenuView.h
#import <UIKit/UIKit.h>
#import "WorkspaceView.h"
#import "MainMenuViewDelegate.h"
#interface MainMenuView : UIView
#property (nonatomic,weak) id <MainMenuViewDelegate> delegate;
....
#end
MainMenuView.m
#implementation MainMenuView
#synthesize delegate;
...
-(void)library:(id)sender{
//test
NSLog(#"it's work");
NSString *string = #"some text";
[delegate mainMenuViewLibrary:self withString:string];
NSLog(#"finish");
}
WorkspaceView.h
#import <UIKit/UIKit.h>
#import "MainMenuViewDelegate.h"
#interface WorkspaceView : UIView <MainMenuViewDelegate> {
int menuStatus;
UILabel *label;
}
#property int menuStatus;
#property (nonatomic, retain) UILabel *label;
#end
WorkspaceView.m
#import "WorkspaceView.h"
#import "MainMenuView.h"
#implementation WorkspaceView
#synthesize menuStatus;
#synthesize label;
....
-(void) mainMenuViewLibrary:(MainMenuView*)controller withString:(NSString*)string{
[label setText: string];
}
#end
The problem appears when i press btnLibrary and invokes -(void)library:(id)sender function.
console print it's work, then my delegate function is invokes, but i don't see any change in my label (placed in WorkspaceView), and in finish console print finish.
None of your objects is set as the delegate so the delegate is nil - messages sent to nil are silenced. Nothing happens.
If it is not a problem, put the NSLog in:
-(void) mainMenuViewLibrary:(MainMenuView*)controller withString:(NSString*)string;
in your WorkspaceView and check whether the method is called.
Hope that helps.