I am developing a game and I have a settings view that is pushed modally. I want if I turn music off in that view, stop the background music. I'm using a protocol (I am using automatic reference counting):
game.h
#import <UIKit/UIKit.h>
#import "AVFoundation/AVFoundation.h"
#import "stackButton.h"
#import "tvr_AppDelegate.h"
#protocol settingsChanger <NSObject>
-(void)changeSettings:(int)soundVal musicSetting:(int)musicVal;
#end
#interface game : UIViewController <UIAlertViewDelegate, settingsChanger>{
...
}
game.m
-(void)changeSettings:(int)soundVal musicSetting:(int)musicVal{
if (musicVal == 1) {
[self playMusic];
}else{
[audioPlayer stop];
}
settings.h
#import <UIKit/UIKit.h>
#protocol settingsChanger;
#interface settings : UIViewController{
id<settingsChanger> settingsDelegate;
}
#property (nonatomic, strong) id<settingsChanger> settingsDelegate;
-(IBAction)updateMusicSetting;
#end
settings.m
-(IBAction)updateMusicSetting{
tvr_AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
if (swMusic.on) {
[delegate updateMusicSetting:1];
[settingsDelegate changeSettings:0 musicSetting:1];
}
else {
[delegate updateMusicSetting:0];
[settingsDelegate changeSettings:0 musicSetting:0];
}
}
My IBAction is triggered by a UISwitch. All goes fine, except that id settingsDelegate references to memory 0x0 and I think that's the my method changeSettings is never called in game.h. What am I missing?.
I would suggest as a good programming practice to name your classes with an uppercase, that is: "Game" instead of "game" and your protocols as well: "SettingsChanger" instead of "settingsChanger". Your method naming conventions seem also to need some improvement, just take 30 minutes time and read Apples "Cocoa Guidelines For Cocoa" link to the "Cocoa Guidelines For Cocoa document"
Related
I'm trying to create an Obj-C, CoreBluetooth virtual peripheral app and get this warning.
//
// ViewController.h
// sim_backend_empty3
//
//
#import <UIKit/UIKit.h>
#import <CoreBluetooth/CoreBluetooth.h>
#interface ViewController : UIViewController <CBPeripheralManagerDelegate>
#property (nonatomic, strong) CBPeripheralManager *peripheralManager;
#end
//
// ViewController.m
// sim_backend_empty3
//
//
#import "ViewController.h"
#implementation ViewController >>>>>>>>>> WARNING >>>>>>>>>> Class 'ViewController' does not conform to protocol 'CBPeripheralManagerDelegate'
- (void)viewDidLoad {
[super viewDidLoad];
}
-(void)start_BLE_advertisements
{
[[CBPeripheralManager alloc] initWithDelegate:self queue:nil options:nil];
}
#end
You need to implement the required CBPeripheralManagerDelegate protocol method:
peripheralManagerDidUpdateState:
as mentioned in the documentation here: https://developer.apple.com/documentation/corebluetooth/cbperipheralmanagerdelegate?language=objc
The protocol’s required one method, peripheralManagerDidUpdateState:, which Core Bluetooth calls whenever the peripheral manager’s state updates to indicate whether the peripheral manager is available.
You can check out an Objective-C example of how to setup CoreBluetooth using this repo:
https://github.com/LGBluetooth/LGBluetooth
Back when I still coded in ObjC, it was the library I used - and it was pretty great.
At the very least, it will give you some ideas on how you should be implementing the interfaces.
Here is a Swift implementation of what it sounds like you're trying to do (based on your other question asked a few days ago). Maybe you can backport it to ObjC (disclaimer: I'm the author).
https://github.com/RobotPajamas/SwiftyTeeth/blob/master/Sources/SwiftyTooth/SwiftyTooth.swift
Before I was using NSNotificationEvents, but as I know I should be using delegate because of 1:1 relations (it will be used only in one place in code).
Basically Im new to objective-C and swift (Im JavaScript guy) and the code that I created after a few hours of reading and checking - it just doesnt work, because self.delegate in not defined.
Im trying to delegate "an event" from objective-C code to swift code. NSNotificationEvents works like charm, but I want to make it with protocols / delegate.
I guess, I just missing how to exactly initialize the delegate protocol.
ProtocolDelegate.h
#import <Foundation/Foundation.h>
#protocol ProtocolDelegate <NSObject>
- (void) delegateMethod: (id)data;
#end
Event.h
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#import "ProtocolDelegate.h"
#interface Event : NSObject <RCTBridgeModule, ProtocolDelegate>
#property(nonatomic, weak)id <ProtocolDelegate> delegate;
#end
Event.m
(someMethod is executed from JavaScript React-native code, but it shouldn't be any difference from what I know)
#import "Event.h"
#implementation Event
RCT_EXPORT_MODULE(Events);
RCT_EXPORT_METHOD(someMethod: (NSString*)parameter) {
NSDictionary* data = #{#"parameter": parameter};
NSLog(#"This I can see");
if ([self.delegate respondsToSelector:#selector(delegateMethod:)]) {
NSLog(#"This I can not see");
[self.delegate delegateMethod:data];
}
}
ViewController.swift
class ViewController: UIViewController, ProtocolDelegate {
// Xcode has automatically created this method
func delegateMethod(_ data: Any!) {
os_log("ON AUCTION");
}
}
I want delegateMethod inside ViewController to be executed.
Or maybe I get the whole idea wrong? Objective-C is a bit confising to me.
it is my first app that I am trying to do on my own and I have some questions. I want to have 4 tabs, and in the first one named "HomeView" I am parsing JSON data (this is done so far).
But what I want is some of the data that are being parsed to be visible in other tabs (and not have to parse them again).
So parts of my code of HomeView is here:
#import "HomeView.h"
#interface HomeView ()
#end
#implementation HomeView
//other code
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
//data fetched
parsed_date=[res objectForKey:#"date"];
NSLog(#"Date:%#",parsed_date);
[UIAppDelegate.myArray addObject:parsed_date];
}
and I can see the "parsed_date" being printed out correctly.
So I want this parsed_date to be visible in OtherView.
This is my code but I cannot print it out.
OtherView.m
#import "OtherView.h"
#import "HomeView.h"
#import "AppDelegate.h"
#interface OtherView ()
#end
#implementation OtherView
#synthesize tracks_date;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
//preview value of other class
tracks_date = [UIAppDelegate.myArray objectAtIndex:0];
NSLog(#"Dated previed in OtherView: %#", tracks_date);
}
and (null) is being printed out.
added code of app delegate.h
#import <UIKit/UIKit.h>
#define UIAppDelegate ((AppDelegate *)[UIApplication sharedApplication].delegate)
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (nonatomic, strong) NSArray *myArray;
#end
So can you suggest me a sollution?
Add the property to your Application Delegate instead.
When assigning the property do something like:
MyAppDelegate *delegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
delegate.myProperty = #"My Value";
then, in your different tabs, you can retrieve this property in the same manner:
MyAppDelegate *delegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
NSString *valueInTab = delegate.myProperty;
Uh, when you create a HomeView in your last code segment there, you're creating a new object -- a new instance of the class. It will not contain the data from connectionDidFinishLoading unless that method is executed in that instance of the class.
You basically need to use some sort of persistence mechanism to do what you want, either the AppDelegate or static storage along the lines of a "singleton".
While this may not be the best method of doing this, it is easy and effective.
Save your data in your app delegate and retrieve it from there. You can create a shortcut to your app delegate shared application. Then just access the values there.
AppDelegate.h
#define UIAppDelegate ((AppDelegate *)[UIApplication sharedApplication].delegate)
#property (nonatomic, strong) NSArray *myArray;
TabView1.m
#import "AppDelegate.h"
SomeObject *myObject = [UIAppDelegate.myArray objectAtIndex:0];
Like I said, it might not be the best way to organize your data for your application, this method does work for small amounts of data needing to be shared at the application level. Hope this helps.
this happens because you create an instance of HomeView yourself.
it has simply no connections to anything.
your first example works because it is the created and initialized from your nib.
i think the best way is to use an IBOutlet and then connect both 'Views' in InterfaceBuilder.
#interface OtherView ()
IBOutlet HomeView *homeView;
#end
#implementation OtherView
#synthesize tracks_date;
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Dated previed in OtherView: %#", homeView.parsed_date);
}
- (void)dealloc:
{
[homeView release];
}
have a look here, it will demonstrate it much more
In InterfaceBuilder you can manage your Objects and connect them (via IBOutlets and IBAction, ...) together.
I think this video is a good demonstration how this concept work.
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 then post the problem in the end
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]; // read testdata
}
#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]; // only a testvalue
return self;
}
#end
the app builds fine, and starts up but the label stays blank. so either the object does not exist (but i guess this would result in an error message), or something else is wrong with my setup. any thoughts?
Two notes:
Your have a shotgun approach to asking questions: everytime you hit a stumbling block, you ask a question and if the answer does not work immediately, you ask another one. You have to spend some energy in between the questions debugging and poking into the code on your own, otherwise you will depend on the external help forever.
Use the common coding style please. CAPS are reserved for macros.
Now to the code:
- (BOOL) …didFinishLaunching…
{
DBFactoryClass *factory = [[DBFactoryClass alloc] init];
return YES;
}
This simply creates an instance of the DBFactoryClass and then throws it away. In other words, it’s essentially a no-op. Judging by the comments in the previous answer you create the controllers using the Storyboard feature. How are they supposed to receive the reference to the data model? The reference isn’t going to show up by magic, you have to assign it somewhere.
I’m not familiar with the Storyboard feature. The way I would do it is to create the view controllers using separate XIB files, then you can create the controller instances in the Factory class and pass them the needed reference to the model. In the end the application delegate would create the factory, ask it to assemble the main controller and then set it as the root view controller for the window. Just like in my sample project. It’s possible that there’s a way to make it work with storyboards, but as I said, I am not familiar with them.
I've googled around and found some answers but I didn't get any of them to work. I have one NSObject with the class "A" and a second class "B" without an NSObject. In class "A" are my IBOutlets defined and I can't seem to figure out how to access those outlets from class "B"...
I've found answered questions like http://forums.macrumors.com/archive/index.php/t-662717.html But they're confusing.
Any help would be greatly appreciated!
Simplified Version of the Code:
aClass.h:
#import <Cocoa/Cocoa.h>
#interface aClass : NSObject {
IBOutlet NSTextField *textField;
}
#end
aClass.m:
#import "aClass.h"
#implementation aClass
// Code doesn't matter
#end
bClass.h:
#import <Cocoa/Cocoa.h>
#interface bClass : NSObject {
}
#end
bClass.m:
#import "aClass.h"
#import "bClass.h"
#implementation bClass
[textField setStringValue: #"foo"];
#end
When you write:
I have one NSObject with the class
"A" and a second class "B" without an
NSObject.
It tells me that you don't have your head around the basic concepts.
Read through Apple's objective-C introduction, and the tutorial projects.
The solution is using NSNotificationCenter. Here's a thread telling you how to do it: Send and receive messages through NSNotificationCenter in Objective-C?
Then in the method reacting to the notification, you call a method accessing the Outlet
- (void) receiveTestNotification:(NSNotification *) notification
{
if ([[notification name] isEqualToString:#"TestNotification"])
//NSLog (#"Successfully received the test notification!");
[self performSelectorOnMainThread:#selector(doIt:) withObject:nil waitUntilDone:false];
}
- (void) doIt
{
//testLabel.text = #"muhaha";
}
This worked for me, I hope it does so for you as well.