iOS call method of another class - ios

I found similar questions on this site but not one that addresses the problem in a clear and basic way.
I have my ReadViewController.h and ReadViewController.m files along with my ChooseViewController.h and ChooseViewController.m files.
They both need to access the getProperties method which is currently in the ReadViewController.m file.
- (void) getProperties {
NSLog(#"Start getProperties");
//SOME CODE
NSLog(#"End getProperties");
}
Now ideally this will be in a third file called GeneralModel.m
Please give me a basic example of what code needs to be in the controller files for them to be able to call this method.

If this method Going to be used in many places in Application then in this case you should treat it as Global method and try to put this method in separate class may be type of NSObject Class.
#interface Utility :NSobject
- (void) getProperties
#end
#implementation Utility
- (void) getProperties {
NSLog(#"Start getProperties");
//SOME CODE
NSLog(#"End getProperties");
}
#end
Here Whenever you need that methods you just need to create the Object of Utility Class can access it easily wherever it needed.like
in ReadViewController just make object and access in this way
Utility * obje = [Utility alloc]init];
[obje getProperties ];
And One thing if you just talking about the App architecture ,Suppose you following the MVC in that Case you should keep your model(NSObject Type)Class for Making some DB call, Request call to server. Keep View Classes code Like UIView separately and put the Code inside Controller class only which needed to control the Logic of App.
Here is the Link which explain The MVC Architecture.
I hope it clears to you.

The solution I've implemented looks like this. I'll accept iOS-Developer's answer though since it set me on the right track.
//*********************
//ReadViewController.h
#import <UIKit/UIKit.h>
#import "GeneralModel.h"
#interface ReadViewController : UIViewController {
GeneralModel *generalModel;
}
#end
//*********************
//*********************
//ReadViewController.m
#import "ReadViewController.h"
#interface ReadViewController ()
#end
#implementation ReadViewController
NSArray *allProperties;
- (void) getProperties {
generalModel = [[GeneralModel alloc] init];
allProperties = [generalModel getProperties];
NSLog(#"ALLPROPERTIES: %#", allProperties);
[generalModel release];
}
//**********************
//**********************
//GeneralModel.h
#import <Foundation/Foundation.h>
#import "sqlite3.h"
#interface GeneralModel : NSObject {
}
-(NSArray *) getProperties;
#end
//**********************
//**********************
//GeneralModel.m
#import "GeneralModel.h"
#implementation GeneralModel
- (NSArray *) getProperties {
NSLog(#"Start getProperties");
NSArray *someProperties;
//Some nice code goes here for getting a lot of nice properties from somewhere else.
return someProperties
NSLog(#"End getProperties");
}
//***********************

If this method Going to be used in many places in Application then in this case you should treat it as Global method and try to put this method in separate class may be type of NSObject Class.
#interface Utility :NSobject
- (void) getProperties
#end
#implementation Utility
- (void) getProperties {
NSLog(#"Start getProperties");
//SOME CODE
NSLog(#"End getProperties");
}
#end
Here Whenever you need that methods you just need to create the Object of Utility Class can access it easily wherever it needed.like
in ReadViewController just make object and access in this way
Utility * obje = [Utility alloc]init];
[obje getProperties ];

Related

Pass Data between two view controllers using 'Delegation' : Objective-C

I am implementing an library(.a), and I want to send notification count from library to app so they can show in their UI, notification count. I want them to implement the only method like,
-(void)updateCount:(int)count{
NSLog(#"count *d", count);
}
How can I send the count from my library continuously so they can use it in updateCount method to show.
I searched and come to know about call back functions. I have no idea how to implement them. Is there any other way to do this.
You have 3 options
Delegate
Notification
Block,also known callback
I think what you want is Delegate
Assume you have this file as lib
TestLib.h
#import <Foundation/Foundation.h>
#protocol TestLibDelegate<NSObject>
-(void)updateCount:(int)count;
#end
#interface TestLib : NSObject
#property(weak,nonatomic)id<TestLibDelegate> delegate;
-(void)startUpdatingCount;
#end
TestLib.m
#import "TestLib.h"
#implementation TestLib
-(void)startUpdatingCount{
int count = 0;//Create count
if ([self.delegate respondsToSelector:#selector(updateCount:)]) {
[self.delegate updateCount:count];
}
}
#end
Then in the class you want to use
#import "ViewController.h"
#import "TestLib.h"
#interface ViewController ()<TestLibDelegate>
#property (strong,nonatomic)TestLib * lib;
#end
#implementation ViewController
-(void)viewDidLoad{
self.lib = [[TestLib alloc] init];
self.lib.delegate = self;
[self.lib startUpdatingCount];
}
-(void)updateCount:(int)count{
NSLog(#"%d",count);
}
#end

Objective C Callback on particular event

I am new to objective C and trying to develop my own callback function, the callback function gets called on a particular event like receiving data from network like NSURLprotocol does and once received it will NSLog a message that "Event has Occured" or display as text on UIViewController or any UI related action.
So, I am totally confused as to where the eventOccuredMethod should be called to let the receiveController be called and execute the implementation inside it.
I have used protocols like NSURLProtocol before, but I don't know how to implement them to get such callbacks being called.
Any video links, answers, articles links are welcomed.
//Sample.h file
#import <Foundation/Foundation.h>
#class Sample;
#protocol SampleProtocol <NSObject>
-(void)receivedCallback;
#end
#interface Sample : NSObject
#property (nonatomic,weak) id<SampleProtocol> delegate;
-(void)eventOccured;
#end
//Sample.m file
#import "Sample.h"
#implementation Sample
-(void)eventOccured{
if([_delegate conformsToProtocol:#protocol(SampleProtocol)])
[_delegate receivedCallback];
}
#end
//ViewController.h file
#interface ViewController : UIViewController<SampleProtocol>
#end
//ViewController.m file
#import "ViewController.h"
#interface ViewController (){
Sample *s;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
s = [[Sample alloc] init];
s.delegate = self;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)receivedCallback:(Sample *)sample{
NSLog(#"Event Has Occured");
}
#end
I am not sure of the following call which I am making ...
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
Sample *s = [[Sample alloc] init];
[s eventOccured];
}
You are implementing the delegate pattern the right way. But if the Sample object doesn't generate its own events but instead is relaying events posted to it from somewhere else, as is the case in your example, you have to ensure that the object which has the ViewController as a delegate and the object that receives the message are in fact the same. One way to do it is to make Sample a singleton :
#import "Sample.h"
#implementation Sample
+ (instancetype)sharedInstance
{
static id sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[[self class] alloc] init];
});
return sharedInstance;
}
-(void)eventOccured{
if([_delegate conformsToProtocol:#protocol(SampleProtocol)])
[_delegate receivedCallback];
}
#end
And then in your view controller you would do
s = [Sample sharedInstance];
and in your appDelegate :
[[Sample sharedInstance] eventOccured];
Another way to ensure that you are using the same object, as vikingosegundo pointed out, would be to set the view controller's Sample object from the appDelegate.
For this use case, you could also consider using Notifications.
?, i'm very confused. I don't think you understand what you have written. You should never try copy code like this from online without first reading a tutorial to understand what it is you are doing. This can be very dangerous.
Sample.h / .m is a class, this class defines a protocol that says "In order for me to alert you to the fact an event has occurred, you need to implement method X".
This is the "protocol", by conforming to the protocol, another class (lets say a ViewController) is saying that it implements the method that Sample is looking for.
So Sample will run code, and when it wants to pass some info back to the other class (ViewController in this case) it calls one of the methods defined in the protocol.
e.g. (not fully working code)
Sample.m
- (void)getDataFromURL:(NSStirng *)url
{
[self HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject)
{
if([_delegate conformsToProtocol:#protocol(SampleProtocol)])
{
[_delegate receivedCallback];
}
}];
}
So when Sample runs the method getDataFromURL it will request its data, when the data returns, Sample will call the method receivedCallback on its delegate. Which in this case is an instance of a viewController.
EDIT
please also note what [_delegate conformsToProtocol:#protocol(SampleProtocol)] does. This asks does the delegate instance conform to the protocol. But this protocol hasn't said that recievedCallback is required. So you have no way of knowing the method is there.
either use:
#protocol SampleProtocol <NSObject>
#required
-(void)receivedCallback;
#end
in the protocol definition or
if(self.delegate && [self.delegate respondsToSelector:#selector(receivedCallback)])
to check is it implemented
you are calling eventOccured on a second, independent Sample instance that has now delegate set.
The easiest fix: make the view controller send it to it's sample instance.
better: give the view controller a property that holds sample and sat that from the application delegate.
You should call EventOccurred within your data retrieving method. Once the data retrieving is complete call EventOccured.
#protocol SampleProtocol <NSObject>
-(void)receivedCallback;
#end
This protocol must be implemented in your data retrieving class. And make sure -(void)receivedCallback; has a parameter to send data to your ViewController

How to use an internal method in a Objective-C category?

Trying to extend the capabilities from a open source project, I wrote a category for add a new method. In this new method, the category needs to access to an internal method from the original class, but the compiler says that it can't find the method (of course, is internal). Is there any way to expose this method for the category?
EDIT
I don't want to modify the original code, so I don't want to declare the internal method in the original class header file.
The code
In the original class implementation file (.m), I have this method implementation:
+(NSDictionary*) storeKitItems
{
return [NSDictionary dictionaryWithContentsOfFile:
[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:
#"MKStoreKitConfigs.plist"]];
}
In the category, I want to add this method:
- (void)requestProductData:(NSArray *(^)())loadIdentifierBlock
{
NSMutableArray *productsArray = [NSMutableArray array];
NSArray *consumables = [[[MKStoreManager storeKitItems] objectForKey:#"Consumables"] allKeys];
NSArray *nonConsumables = [[MKStoreManager storeKitItems] objectForKey:#"Non-Consumables"];
NSArray *subscriptions = [[[MKStoreManager storeKitItems] objectForKey:#"Subscriptions"] allKeys];
if(loadIdentifierBlock != nil) [productsArray addObjectsFromArray:loadIdentifierBlock()];
[productsArray addObjectsFromArray:consumables];
[productsArray addObjectsFromArray:nonConsumables];
[productsArray addObjectsFromArray:subscriptions];
self.productsRequest.delegate = self;
[self.productsRequest start];
}
In every line in which I call storeKitItemscompiler says: Class method "+storeKitItems" not found ...
This is trivial, make a forward declaration of the method.
Unfortunately, in obj-c, every method declaration must be inside #interface, so you can make it work in your category .m file with another internal category, e.g.
#interface MKStoreManager (CategoryInternal)
+ (NSDictionary*)storeKitItems;
#end
No implementation is needed, this only tells the compiler the method is somewhere else, similarly to #dynamic with properties.
If you are only interested in removing the warning, you can also just cast the class to id, the following should work, too:
NSDictionary* dictionary = [(id) [MKStoreManager class] storeKitItems];
However, my favorite solution is to do it a bit differently, let's assume the following example:
#interface MyClass
#end
#implementation MyClass
-(void)internalMethod {
}
#end
#interface MyClass (SomeFunctionality)
#end
#implementation MyClass (SomeFunctionality)
-(void)someMethod {
//WARNING HERE!
[self internalMethod];
}
#end
My solution is to split the class into two parts:
#interface MyClass
#end
#implementation MyClass
#end
#interface MyClass (Internal)
-(void)internalMethod;
#end
#implementation MyClass (Internal)
-(void)internalMethod {
}
#end
And include MyClass+Internal.h from both MyClass.m and MyClass+SomeFunctionality.m
A category has no access to the private methods of a class. It's no different than trying to call those methods from any other class. At least if you call the private method directly. Since Objective-C is so dynamic, you can call private methods (which is a bad idea) using other means such as using performSelector or with NSInvocation.
Again, this is a bad idea. An update to the implementation of the class could break your category.
Edit: Now that there is code posted -
Since the +storeKitItems method is not declared in the .h file, no category or other class can access the private method.
In you category implementation file you can define and informal protocol for the method
#interface YourClasses (ExternalMethods)
+(NSDictionary*) storeKitItems;
#end
This will stop the compiler from complaining about not knowing of the method storeKitItems in you category.

iOS method in data controller isn't being called

I am trying to call a method in my data controller object to load the data for my application, but for some reason it is not being called. Below is what I have done to initialize it. Any help would be greatly appreciated.
ViewController:
header file:
#import <UIKit/UIKit.h>
#class DetailViewController;
#class DataController;
#import <CoreData/CoreData.h>
#import "JointCAD.h"
#interface TableViewController : UITableViewController {
}
#property (nonatomic, assign) DataController *dataController;
#end
implementation file:
#import "TableViewController.h"
#import "DataController.h"
#implementation TableViewController
#synthesize dataController;
- (void)viewDidLoad {
[dataController refreshData];
}
#end
Data Controller:
header file:
#import <Foundation/Foundation.h>
#import "JointCAD.h"
#import "JointCADXMLParser.h"
#import "TFHpple.h"
#interface DataController : NSObject {
TFHpple *xpathParser;
}
- (void)refreshData;
- (void)initXMLParser;
- (void)noCallsMessage;
- (void)noInternetMessage;
#end
implementation file:
#import "DataController.h"
#implementation DataController
XMLParser *xmlParser;
- (void)refreshData {
NSLog("Some Method");
}
Is 'dataController' Object being set by some other class? - I believe that's why you have set it as a property? Right?
If No, then Remove the property,#synthesize of 'dataController' and try simple allocation of your 'dataController' object and then try calling your method.
Hope it helps.
You either need to initialize "DataController" prior to actually calling one of it's methods, or you need to make the method, "refreshData" a class by changing it's "-" to a "+".
If you need an instance callback instead. You need to rewrite "viewDidLoad" like this:
- (void)viewDidLoad {
DataController *dataController = [[DataController alloc] init];
[dataController refreshData];
}
And get rid of the property declaration of dataController because you haven't initialized it. If you would prefer a property declaration instead, simply allocate the viewcontroller prior to calling a function from it.
- (void)viewDidLoad {
dataController = [[DataController alloc] init];
[dataController refreshData];
}
One last thing to note is that I (and probably Ray) assume that you're using a storyboard configuration. If you are using a xib configuration, you need to add initWithNibName: to each initialization of the view controller.
I hope that's helpful!

Delegate declaration dilemma

I'm confused - I cannot understand what is the delegate is for?
The Application Delegate which is created by default is understandable, but in some cases I've seen something like this:
#interface MyClass : UIViewController <UIScrollViewDelegate> {
UIScrollView *scrollView;
UIPageControl *pageControl;
NSMutableArray *viewControllers;
BOOL pageControlUsed;
}
//...
#end
What is the <UIScrollViewDelegate> for?
How does it work and why is it used?
<UIScrollViewDelegate> is saying that the class conforms to the UIScrollViewDelegate protocol.
What this really means is that the class must implement all of the required methods defined within the UIScrollViewDelegate protocol. Simple as that.
You can conform your class to multiple protocols if you like:
#implementation MyClass : UIViewController <SomeProtocol, SomeOtherProtocol>
The purpose of conforming a class to a protocol is to a) declare the type as a conformant of the protocol, so you can now categorize this type under id <SomeProtocol>, which is better for delegate objects that objects of this class may belong to, and b) It tells the compiler to not warn you that the implemented methods are not declared in the header file, because your class conforms to the protocol.
Here's an example:
Printable.h
#protocol Printable
- (void) print:(Printer *) printer;
#end
Document.h
#import "Printable.h"
#interface Document : NSObject <Printable> {
//ivars omitted for brevity, there are sure to be many of these :)
}
#end
Document.m
#implementation Document
//probably tons of code here..
#pragma mark Printable methods
- (void) print: (Printer *) printer {
//do awesome print job stuff here...
}
#end
You could then have multiple objects that conform to the Printable protocol, which could then be used as an instance variable in, say, a PrintJob object:
#interface PrintJob : NSObject {
id <Printable> target;
Printer *printer;
}
#property (nonatomic, retain) id <Printable> target;
- (id) initWithPrinter:(Printer *) print;
- (void) start;
#end
#implementation PrintJob
#synthesize target;
- (id) initWithPrinter:(Printer *) print andTarget:(id<Printable>) targ {
if((self = [super init])) {
printer = print;
self.target = targ;
}
return self;
}
- (void) start {
[target print:printer]; //invoke print on the target, which we know conforms to Printable
}
- (void) dealloc {
[target release];
[super dealloc];
}
#end
I think you need to understand the Delegate Pattern. It is a core pattern used by iphone/ipad applications and if you don't understand it you will not get far. The link to wikipedia I just used outlines the pattern and gives examples of it's use including Objective C. That would be a good place to get started. Also look at take a look at the Overview tutorial from Apple which is specific to the iPhone and also discusses the Delegate pattern.

Resources