So I've built a few apps and am now trying my hand at building a piece of iPhone code that others can drop into their applications. Question is how do I hide the data elements in an object class header file (.h) from the user?
For example, not sure if people have used the medialets iPhone analytics but their .h does not have any data elements defined. It looks like:
#import <UIKit/UIKit.h>
#class CLLocationManager;
#class CLLocation;
#interface FlurryAPI : NSObject {
}
//miscellaneous function calls
#end
With that header file, they also supply an assembly file (.a) that has some data elements in it. How do they maintain those data elements across the life span of the object without declaring them in the .h file?
I am not sure if it matters but the .h file is only used to create a singleton object, not multiple objects of the same class (FlurryAPI).
Any help would be much appreciated. Thanks
Take a look at this:
Hide instance variable from header file in Objective C
In my header file I'd have:
#interface PublicClass : NSObject
{
}
- (void)theInt;
#end
In my source file I'd have:
#interface PrivateClass : PublicClass
{
int theInt;
}
- (id)initPrivate;
#end;
#implementation PublicClass
- (int)theInt
{
return 0; // this won't get called
}
- (id)init
{
[self release];
self = [[PrivateClass alloc] initPrivate];
return self;
}
- (id)initPrivate
{
if ((self = [super init]))
{
}
return self;
}
#end
#implementation PrivateClass
- (int)theInt
{
return theInt; // this will get called
}
- (id)initPrivate
{
if ((self = [super initPrivate]))
{
theInt = 666;
}
return self;
}
#end
I'm using theInt as an example. Add other variables to suit your taste.
I recommend you to use categories to hide methods.
.h
#import <Foundation/Foundation.h>
#interface EncapsulationObject : NSObject {
#private
int value;
NSNumber *num;
}
- (void)display;
#end
.m
#import "EncapsulationObject.h"
#interface EncapsulationObject()
#property (nonatomic) int value;
#property (nonatomic, retain) NSNumber *num;
#end
#implementation EncapsulationObject
#synthesize value;
#synthesize num;
- (id)init {
if ((self == [super init])) {
value = 0;
num = [[NSNumber alloc] initWithInt:10];
}
return self;
}
- (void)display {
NSLog(#"%d, %#", value, num);
}
- (void)dealloc {
[num release];
[super dealloc];
}
#end
You can't access to the private instance variables via dot notation, but you can still get the value by using [anObject num], though the compiler will generate a warning. This is why our apps can get rejected by Apple by calling PRIVATE APIs.
Related
I started testing ECSlidingViewController and after I tried to access FirstTopViewController I have a big trouble - because in FirstToViewController I already have ZBarReaderDelegate implemented and all examples of delegate are not triggering any method from my delegate.
Basically I have this stuff:
FirstTopViewController.h
#import ...MyStuff...
#import "UnderRightViewController.h"
#interface FirstTopViewController : UIViewController <RightViewDelegate, ZBarReaderDelegate>
#property (weak, nonatomic) IBOutlet UITextView *labelTotal;
#end
FirstTopViewController.m
#import "FirstTopViewController.h"
#implementation FirstTopViewController
- (void)setTotalViewController:(UnderRightViewController*)controller didTotalChange:(NSString*)total
{
//labelTotal.text = total;
NSLog(#"I'm here!!! and received %#", total);
}
From other side I have
UnderRightViewController.h
#import <UIKit/UIKit.h>
#import "ECSlidingViewController.h"
#class UnderRightViewController;
#protocol RightViewDelegate <NSObject>
- (void)setTotalViewController:(UnderRightViewController*)controller didTotalChange:(NSString*)total;
#end
#interface UnderRightViewController : UITableViewController
#property (nonatomic, weak) id <RightViewDelegate> delegate;
#end
UnderRightViewController.m
#import "UnderRightViewController.h"
#interface UnderRightViewController ()
#end
#implementation UnderRightViewController
#synthesize delegate;
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[delegate setTotalViewController:self didTotalChange:#"foo"];
}
#end
I'm trying this entire day solve this puzzle but I never get setTotalViewController fired.
Thanks in advance.
Friend you did a small mistake, when you navigate from FirstTopViewController to UnderRightViewController at that time you need to do this in FirstTopViewController.m:-
UnderRightViewController *obj = [[UnderRightViewController
alloc] initWithNibName:#"UnderRightViewController" bundle:nil];
obj.delegate = self; // u forget to assign protocol handler
[self.navigationController pushViewController:obj animated:YES];
[obj release];
You don't have any code that is setting the delegate for the UnderRightViewController. I don't know what object owns both of these controllers, but before either UnderRightViewController and FirstTopViewController are displayed it should run code something like this:
FirstTopViewController *ftvc = //... where ever you get a reference to this from
UnderRightViewController *urvc = ...;
urvc.delegate = ftvc;
In your above code you are using custom delegates and also you have used it for sending message to onecontroller class to another controller class. So below is the same sample code of custom delegates, it is working fine in similar way you have to implement and also the problem in your code is you are not setting the delegate, so please follow below how to set the same and call the method. here i have used your same method only return type i have defined as NSString in-spite of void for explaining purpose, but you can use void according to your requirement hope it will be helpful to you:-
First Controller Class AWindowController.h
#interface AWindowController : NSWindowController<sampleDelegate>
{
NSString *textA;
}
#property(readwrite,retain)NSString *textA;
-(IBAction)doSet:(id)sender;
#end
#import "AWindowController.h"
#import "BWindowController.h"
#interface AWindowController ()
#end
#implementation AWindowController
#synthesize textA;
- (id)initWithWindow:(NSWindow *)window
{
self = [super initWithWindow:window];
if (self) {
// Initialization code here.
}
return self;
}
- (NSString *)setTotalViewController:(BWindowController*)controller didTotalChange:(NSString*)total
{
NSLog(#"recieved");
return #"recieved";
}
- (void)windowDidLoad
{
[super windowDidLoad];
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
-(NSString*)windowNibName
{
return #"AWindowController";
}
-(IBAction)doSet:(id)sender
{
[self setTextA:#"Awindow Button Pressed"];
BWindowController *b=[[BWindowController alloc]init];
b.delegate=self;
[b showWindow:self];
}
#end
Second Controller Class BWindowController.h
#import <Cocoa/Cocoa.h>
#import "sampleDelegate.h"
#class BWindowController;
#protocol sampleDelegate <NSObject>
#required
//-(NSString *)getDataValue;
- (NSString *)setTotalViewController:(BWindowController*)controller didTotalChange:(NSString*)total;
#end
#interface BWindowController : NSWindowController<sampleDelegate>
{
NSString *bTextValue;
id<sampleDelegate>delegate;
}
#property(readwrite,retain)NSString *bTextValue;
#property(readwrite,assign)id<sampleDelegate>delegate;
#end
#import "BWindowController.h"
#interface BWindowController ()
#end
#implementation BWindowController
#synthesize bTextValue,delegate;
- (id)initWithWindow:(NSWindow *)window
{
self = [super initWithWindow:window];
if (self) {
// Initialization code here.
}
return self;
}
- (NSString *)setTotalViewController:(BWindowController*)controller didTotalChange:(NSString*)total;
{
return nil;
}
- (void)windowDidLoad
{
NSString *str= [[self delegate]setTotalViewController:self didTotalChange:#"recieved"];
self.bTextValue=str;
[super windowDidLoad];
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
-(NSString*)windowNibName
{
return #"BWindowController";
}
#end
Attached screen shot in Output:-
Below is window is the AwindowController.h class
Below in the same above window pressing the button and when Awindow button pressed data will send
and notification will be recieved in Bwindow using above define custom delegates as attached in the screen shot.
I want to make a library that I can reuse over and over to speed up my development, add to new projects if I wish. Basically I want to build an abstraction layer. Can someone show me how I would do that and why this this portion of code:
if ([self.delegate respondsToSelector:#selector(enableCamera)]) {
BOOL enabled;
enabled = [self.delegate enableCamera];
if (enabled == YES) {
[self enableCameraMethod];
}
does not get called?
HERES MY CODE BELOW:
library.h:
#protocol usesCamera <NSObject>
#optional
-(BOOL)enableCamera;
#end
#interface Library : NSObject
#property (nonatomic, weak) id <usesCamera> delegate;
-(void)enableCameraMethod;
#end
library.m
#import "Library.h"
#implementation Library
- (id) init
{
if (self = [super init]) {
if ([self.delegate respondsToSelector:#selector(enableCamera)]) {
BOOL enabled;
enabled = [self.delegate enableCamera];
if (enabled == YES) {
[self enableCameraMethod];
}
}
return (self);
}
}
-(void)enableCameraMethod {
NSLog(#"Implement my camera method here");
}
#end
UIViewController.h
#import <UIKit/UIKit.h>
#import "Library.h"
#interface ViewController : UIViewController <usesCamera>
#end
UIViewController.m
#import "ViewController.h"
#import "Library.h"
#interface ViewController ()
#property (nonatomic, strong) UIViewController *myVC;
#end
#implementation ViewController
-(BOOL)enableCamera {
return YES;
}
- (void)viewDidLoad
{
[super viewDidLoad];
Library *myLibrary = [[Library alloc] init];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
did you set your delegate for myLibrary instance in your ViewController class.
you have to do something like this:
Library *myLibrary = [[Library alloc] init];
myLibrary.delegate = self;
As init is called before setting the delegate, so it might not worked, instead of defining the logic in init function create another method and call this method after setting the delegate.
hi i'm wondering category in objective-c
i have 3 files
A_ViewController
A_ViewController+Category
B_ViewController
here's example code
1-1. A_ViewController.h
#interface A_ViewController {
// some instance Variables
}
//some public methods
#end
1-2 A_ViewController.m
#import "A_ViewController.h."
#implementation A_ViewController
// implementation public methods and private methods
#end
2-1. A_ViewController+Category.h
#interface A_ViewControler(Category)
-(void) categoryMethod;
#end
2-2. A_ViewController+Category.m
#import "A_ViewController.h"
#import "A_ViewController+Category.h"
#implementation A_ViewController(Category)
-(void) categoryMethod {
NSLog(#"it's A_ViewController+Category");
}
#end
3-1. B_ViewController.h
#interface B_ViewController {
// some instance variables
}
-(void) myMethod;
3-2. B_ViewController.m
#import "B_ViewController.h"
#import "A_ViewController.h"
#interface A_ViewController() // i think it's A_ViewController extension, not A_ViewController+Category, am i right?
-(void) categoryMethod;
#end
#implementation B_ViewController
-(void) myMethod
{
A_ViewController *obj = [[A_ViewController alloc] init];
[obj categoryMethod];
}
#end
i thought it's crashed because i'm not import A_ViewController+Category.h
and i'm not implement -(void) categoryMethod in B_ViewController.m
but it works fine, and no warning.
how [obj categoryMethod] can be linked??
if that's perfectly fine syntax, i have extension question.
if i have another category called A_ViewController+Category2
here's A_ViewController+Category.h
#interface A_ViewController(Category2)
-(void) categoryMethod;
#end
and A_ViewController+Category2.m
#import "A_ViewController.h"
#import "A_ViewController+Category2.h"
#implementation A_ViewController(Category2)
-(void) categoryMethod
{
NSLog(#"it's A_ViewController+Category2");
}
#end
and this situation, if i write a code like 3-2,
then [obj categoryMethod] can' be guaranteed
that comes from A_ViewController+Category or A_ViewController+Category2, right?
I'm struggling slightly to work out what you're trying to do but in regard to standard category behaviour.
If you want to call categoryMethod on an instance of A_ViewController from within B_BiewController you need to import the header that contains the category method #interface.
You can't declare the private category () on A_ViewController from within B_ViewController.m, as the private category or class extension is a special category.
B_ViewController.m should look like this
#import "B_ViewController.h"
#import "A_ViewController+Category.h"
#implementation B_ViewController
- (void) myMethod {
A_ViewController *obj = [[A_ViewController alloc] init];
[obj categoryMethod];
}
#end
Edit
I've just noticed your Category2 method name is the same as your Category method name. This is incorrect and undefined behaviour in Objective C.
I have a very simple class (currently used as a testing class), which uses delegate/protocol methods to interface with it's parent class. However, I would really like to convert this to use blocks. Yet I can't find a good resource or tutorial out there to help me figure out how to do this. All the blocks tutorials are just way to complicated, and I would really just like a small, concise example of how to do this.
I currently have the class:
#import <Foundation/Foundation.h>
#protocol TestObjectDelegate <NSObject>
#optional
-(void)testObjectSucceeded:(BOOL)passedTest;
-(void)testObjectedFailed:(NSError *)error;
#end
#interface TestObject : NSObject {
id<TestObjectDelegate> _delegate;
}
-(void)compare:(NSString *)stringA with:(NSString *)stringB;
#end
#import "TestObject.h"
#implementation TestObject
- (id)initWithDelegateController:(id<TestObjectDelegate>)delegate {
self = [super init];
if (self) {
_delegate = delegate;
}
return self;
}
-(void)compare:(NSString *)stringA with:(NSString *)stringB {
if ([stringA isEqualToString:stringB]) {
if(_delegate && [_delegate respondsToSelector:#selector(testObjectSucceeded:)]) {
[_delegate testObjectSucceeded:YES];
}
else {
[_delegate testObjectSucceeded:NO];
}
}
else {
if(_delegate && [_delegate respondsToSelector:#selector(testObjectedFailed:)]) {
[_delegate testObjectedFailed:nil];
}
}
}
#end
How could I begin to convert this to a blocks based function? Also, I know 'retain cycles' are something to watch out for when implementing a blocks function. What would I need to watch out for when converting this class to use blocks instead of delegate/protocols? Googling 'retain cycles' also gives some overly complicated answers.
Any starting pointers would be much appreciated?
Maybe this example gives you an idea:
typedef void (^MyCallbackBlock)(BOOL);
#interface TestObject : NSObject {
}
#property (nonatomic, copy) MyCallbackBlock myBlock;
#end
#import "TestObject.h"
#implementation TestObject
-(void) yourMethod
{
...
self.myBlock(YES); // call block with argument
...
}
- (void)dealloc
{
[myBlock release];
myBlock = nil;
[super dealloc];
}
#end
When using the object you can then define the block like this:
TestObject* theTestObject = [[TestObject alloc] init];
theTestObject.myBlock = ^(BOOL theParameter){
NSLog(#"foo");
};
I've reviewed (and tried) a bunch of the threads here regarding Singletons and NSMutableArrays. I'm new to Objective-C so please bear with me.
I simply want to create a few arrays that can be accessed from any view/.m file.
What is the best (or most concise) coding for a Singleton?
Below is what I have now and I get
1 warning at .m '#implementation' - "Incomplete implementation"
1 error at usage in a view .m file - "initializer element is not a compile-time constant"
This is the code I have now - my GlobalData.h file:
#import <Foundation/Foundation.h>
#interface GlobalData : NSObject {
NSMutableArray *listOfHeadings;
NSMutableArray *listOfItems1;
NSMutableArray *listOfItems2;
}
#property(nonatomic,retain)NSMutableArray *listOfHeadings;
#property(nonatomic,retain)NSMutableArray *listOfItems1;
#property(nonatomic,retain)NSMutableArray *listOfItems2;
+(GlobalData*)getInstance;
#end
My GlobalData.m file:
#import "GlobalData.h"
#implementation GlobalData
#synthesize listOfHeadings;
#synthesize listOfItems1;
#synthesize listOfItems2;
static GlobalData *instance=nil;
+(GlobalData *)getInstance
{
#synchronized(self)
{
if(instance==nil)
{
instance= [GlobalData new];
}
}
return instance;
}
#end
And in a view .m file (simplified):
#import GlobalData.h
GlobalData *globDat=[GlobalData getInstance]; //error occurs here
Can someone point out the trouble and if there's better coding, please enlighten me - thanks!
EDIT
Here's a few links I've tried to use:
Can i have a single NSMutableArray in my multiple views application?
iPhone help with singleton class
In this case, you might be doing more than you have to. Granted this certainly isn't always the best solution - but you can put your NSMutableArray as a property in your App Delegate and then easily refer to it from any view. By doing it this way - you aren't locking it in as a 'singleton' but there is a 'singleton instance' of it (this helps a great deal for testability).
I have simplified this process here:
YourAppDelegate.h
#property (nonatomic,retain) NSMutableArray *myArray;
YourAppDelegate.m
#synthesize myArray;
YourViewController.m
YourAppDelegate *appDelegate = (YourAppDelegate *)[[UIApplication sharedApplication] delegate];
NSMutableArray *myArrayFromAppDelegate = appDelegate.myArray;
From this point - you can do any manipulation on this value.
Here's the "modern" version of a single method to turn any class into a Singleton (in this case formatted as a code snippet). It works in iOS4.x or higher:
+(<#SingletonClassName#> *) sharedInstance
{
static <#SingletonClassName#> *_sharedClient = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedClient = [[self alloc] init];
});
return _sharedClient;
}
But, do you really need a singleton of a single NSMutableArray? You could use the built-on singleton - your application delegate, which is got to by calling:
MyAppDelegate * appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.myMutableArray addObject:...];
The error initializer element is not a compile-time constant is not related to how you create your singleton. The error is how you are accessing your singleton. You are doing this outside of a function:
GlobalData *globDat=[GlobalData getInstance];
This means that you are trying to initialize a global variable (globDat) as the value of the expression [GlobalData getInstance]. You can only initialize global variables to expressions that are "compile-time constants". That means things like 0 or "fred" or 8/2. The value of [GlobalData getInstance] cannot be computed at compile-time, so it cannot be used to initialize the global variable.
Instead, you need to just use [GlobalData getInstance] inside your function bodies wherever you are currently trying to use the globDat variable.
As for the warning, Incomplete implementation, I don't see what's missing. Perhaps you didn't post all of the code from GlobalData.h. Anyway, you should be able to click the warning (where it appears on the right side of the editor window) and have Xcode show you what's missing.
This is the way I create my Singleton:
Singleton.h
#import <Foundation/Foundation.h>
#interface Singleton : NSObject {
NSMutableArray *firstMutableArray;
NSMutableArray *secondMutableArray;
}
#property (nonatomic, retain) NSMutableArray *firstMutableArray;
#property (nonatomic, retain) NSMutableArray *secondMutableArray;
+ (id)sharedSingleton;
#end
Sigleton.m
#import "Singleton.h"
static Singleton *sharedMySingleton = nil;
#implementation Singleton
#synthesize firstMutableArray;
#synthesize secondMutableArray;
#pragma mark Singleton Methods
+ (id)sharedSingleton {
#synchronized(self) {
if (sharedMySingleton == nil) {
sharedMySingleton = [[super allocWithZone:NULL] init];
}
return sharedMySingleton;
}
+ (id)allocWithZone:(NSZone *)zone {
return [[self sharedSingleton] retain];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX;
}
- (oneway void)release {
// Never release
}
- (id)autorelease {
return self;
}
- (id)init {
if (self = [super init]) {
firstMutableArray = [[NSMutableArray alloc] initWithObjects:nil];
secondMutableArray = [[NSMutableArray alloc] initWithObjects:nil];
}
return self;
}
- (void)dealloc {
[firstMutableArray release];
[secondMutableArray release];
[super dealloc];
}
#end
Then, when you want to call your Singleton:
#import "Singleton.h"
Singleton *singleton = [Singleton sharedSingleton];
singleton.firstMutableArray = ...
singleton.secondMutableArray = ...