How to Pass Parameter to external class method? - ios

I am trying to do very simple operation.
in "TestFile.h" file i've declare property:
#property (nonatomic) NSDictionary *justTest;
and in implementation file "TestFile.m":
-(NSDictionary *)justTest:(NSString *) mystring {
NSLog(#"Here is my string: %#", mystring);
return nil;
}
Now i am trying to call "justTest" from another file. What i am doing:
#import "TestFile.h"
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSDictionary *testFile = [[TestFile alloc] init];
[testFile justTest:#"Hello World!"]
}
This works fine until i'm trying to pass parameter.
if i just execute
[testFile justTest];
it works, but when i try to pass parameter
[testFile justTest:#"Hello World!"];
does not work and the debug message is:
no visible #interface for 'TestFile' declares the selector 'justTest':
What is wrong with me?

You need to make this method public by adding method name to TestFile.h file before #end:
-(NSDictionary *)justTest:(NSString *) mystring;
Just to let you know when you add #property compiler synthesise it (create) two method getter, exactly the same name as your property and setter compiler add 'set' prefix, for example, you declare:
#property (nonatomic) NSDictionary *justTest;
compiler will create two methods:
-(NSDictionary *)justTest {...}
-(void)setJustTest {...}
You need to know that in your code you override the getter method.

Declare your method in TestFile.h file before calling from an external class.
-(NSDictionary *)justTest:(NSString *) mystring;

Related

Initialize generic parameters in iOS

I want to create object of generic property with default initializer. I know this is possible in swift by adding an init method in MyProtocol. Is there any way I can achieve this functionality in objective c
Interface
#interface CustomClass<__covariant T:id<MyProtocol>> : NSObject
#property(nonatomic) T result;
-(void) update;
#end
Implementation
#import "CustomClass.h"
#implementation CustomClass
-(void) update
{
//self.result = initialize result here
[self.result myMethod];
}
#end
Objective-C is late binding and dynamic typing. Neither you need templates (ooops, they call it generics) nor the compiler bind to it. Simply use id.
#interface CustomClass : NSObject
#property(nonatomic) id result;
-(void) update;
#end
-(void) update
{
//self.result = initialize result here
[self.result myMethod];
}
If you want to have a constraint on the type for whatever reason, simply use the protocol:
#protocol CustomProtocol
- (void)myMethod;
#end
#interface CustomClass : NSObject
#property(nonatomic) id<MyProtocol> result;
-(void) update;
#end
-(void) update
{
//self.result = initialize result here
[self.result myMethod];
}
After discussion the subject in the comments:
If you want to instantiate a generic type, you do not do this at compile time, but simply pass the type to the initializer at runtime.
Instead of …:
var concrete = CustomClass<Concrete>()
… you write:
CustomClass *concrete = [[CustomClass alloc] initForType:[Concrete class]];
Personally I prefer new allocators, but this is another discussion. You can pass the types name as string, too. Personally I do not like that, too. :-)
The initializer looks like this:
- (instancetype)initForType:(Class)type
{
if( (self = [super init] )
{
self.result = [type new];
}
return self;
}
Lightweight generics in Objective-C are a purely compile-time construct to aid in type checking. They are erased after type-checking and do not exist in the compiled code. There is no T at runtime. You cannot write any code that needs to know what T is.

Can I declare a non-public method in an Objective C Category, and if so, how?

To work with JSON data I receive from the AFNetworking library in my app, I'm defining a category on NSDictionary in a file NSDictionary+JSON.h:
#interface NSDictionary (JSON)
- (NSString *) name;
- (NSString *) extension;
...
#end
In my implementation of these methods, I want to declare and use a helper method that I don't want to put in the header file, because it's an implementation detail only:
- (NSString *) valueForKeyFromDictionaryOrIndexes:(NSString *)key;
My implementation file NSDictionary+JSON.m looks like this:
#import "NSDictionary+JSON.h"
#interface NSDictionary()
// Putting my method declaration here produces a warning.
...
#end
#implementation NSDictionary (JSON)
- (NSString *) valueForKeyFromDictionaryOrIndexes:(NSString *)key {
NSString * value = [self valueForKey:key];
// implementation details omitted
return value;
}
- (NSString *) name {
return [self valueForKeyFromDictionaryOrIndexes:#"Name"];
}
- (NSString *) extension {
return [self valueForKeyFromDictionaryOrIndexes:#"Extension"];
}
...
#end
This works fine, so in that sense there is no real problem. But: my helper method has never been declared before being defined. I feel a bit uncomfortable about that. If I put the declaration within the #interface ... #end part in the implementation file, at the comment position (which I assumed would be the correct place to declare a non-public method), I receive a warning:
category is implementing a method which will also be implemented by its primary class
I tried fixing that by replacing
#interface NSDictionary()
with
#interface NSDictionary(JSON)
but that, of course, gives me a different warning:
duplicate definition of category 'JSON' on interface 'NSDictionary'
Fair enough, that's indeed the same as the one in my header file, so that's not a proper solution. Which leaves me wondering: what's the proper way/place to declare a non-public method in a category implementation?
There's no need at all to declare a "private" Obj-C method inside your #interface.

Objective-C properties and instance variables

Problem
I want to create an interface with this signature, but without auto-synthesized instance variables:
#interface MyObject : NSObject
#property (nonatomic, copy) NSArray *values;
#end
Question:
Is it possible to prevent instance variable to be auto synthesized in .m #implementaion, as I want to implement my own getter and setter and I'm not going to use instance variable.
Reason:
The reason is that I don't want to have memory overhead, as data is going to be stored in plain bytes archive. At the same time I don't want users to know implementation issues and keep interface signature unchanged.
#implementation MyObject {
NSData *_data
{
- (NSArray *)values
{
// Generate NSArray from _data
}
- (void)setValues(NSArray *)values
{
// Set _data from values
}
#pragma mark - Hidden init
- (id)initWithData:(NSData *)data
{
// Set _data
}
#end
If you implement both getter and setter yourself, instance variables are not synthesized.
As others said - if you override the setter and getter - the compiler does't do anything else. So what you want.. is what you have typed out.
If you dont wantbto create just create only instance variable.
#interface MyObject : NSObjet
{
NSArray *values;
}
#end

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.

Get variable value from another void

I just started programming in XCode and I need your help.
I have two voids; in the first void I create a NSString, and in the second void I need the value of that string, but i don't know how to obtain that value.
This is a shortend version of my .h file
//.h file
-(void)viewDidLoad
{
[self ActionOne];
}
-(IBAction)ButtonClick (id):sender
{
[self ActionTwo];
}
-(void)ActionOne
{
NSString *VarString = #"hello";
}
-(void)ActionTwo
{
NSLog (#"%#", VarString);
}
My problem is that NSLog's output is 'null', I hope someone can help me
You have declared a local variable in ActionOne. It only lives as long as the method is running. For persistent storage, you need an ivar (that's a term used in Objective-C to mean an "instance variable", which is a variable for which there is a separate copy for each object that is an instance of a class). The easiest way to do this is to declare a property, which will create an ivar and methods to access it for reading and writing. In your .h file:
#interface MyViewController: UIViewController
#property (nonatomic, strong) NSString *varString;
// ... method declarations, etc
#end
And then in your .m file:
-(void)actionOne
{
self.varString = #"hello";
}
-(void)actionTwo
{
NSLog(#"%#", self.varString);
}

Resources