Obj-C Private Method Compiler Warnings - xcode

Private methods are a useful construct to keep code organised within class boundaries. An example being the organisation of long winded Quartz 2d instructions in a custom UIView subclass. I am able to include such methods in '.m' files with no declaration in '.h'. A working example from a UIView subclass '.m' file reads:
-(void)DoSomethingPrivate { //Not declared in interface
NSLog(#"Does this print a private function?");
}
- (id)initWithFrame:(CGRect)frame //Declared in inherited interface
{
self = [super initWithFrame:frame];
if (self) {
[self DoSomethingPrivate]; //Error: 'Instance method not found'
} //... but it works anyway.
return self;
}
My problem is that the compiler generates the warning "Instance method '-DoSomethingPrivate' not found (return type defaults to 'id')" on the line calling the private function. I'm aware from responses to this question that I can use a 'no name' interface category to 'hide' private method declarations.
However, when I review Apple sample code SimpleStocks, file "SimpleStockView.m", it contains a private function which is neither declared in a no-name category interface, nor does it generate compiler warnings:
//Private Function
- (void)drawRadialGradientInSize:(CGSize)size centeredAt:(CGPoint)center {
...
}
//Is called by this function...
- (UIImage *)patternImageOfSize:(CGSize)size {
...
//The next line doesn't generate any warnings!
[self drawRadialGradientInSize:size centeredAt:center];
...
}
I'd be grateful if anyone can shed any light on how Apple's sample-code private-methods appear to escape compiler checks, so I may avoid having to maintain a 'no-name' category header with all my private methods.
Many thanks.

Related

Xamarin iOS binding library duplicated constructors issue

I have an issue with duplicated constructor in Xamarin iOS binding library with code generated by sharpie tool from third-party SDK code. Basicly C# generated interface is using NSFileHandle as a base type and SDK header file declares identical designated initializer in its subclass like in NSFileHandler so I'm getting "Member ... is already defined error" because now binding library is generating C# constructor twice - first time from the base class and the second from subclassed initializer.
Objective-C code:
#interface MyFileHandle : NSFileHandle
//...
- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
//...
C# binding library code:
[BaseType(typeof(NSFileHandle))]
public interface MyFileHandle
{
//...
[Export("initWithCoder:")]
[DesignatedInitializer]
IntPtr Constructor(NSCoder coder);
//...
}
Binding library generated code (*.g.cs):
[Register("MyFileHandle", true)]
public unsafe partial class MyFileHandle : NSFileHandle {
//...
[CompilerGenerated]
[DesignatedInitializer]
[EditorBrowsable (EditorBrowsableState.Advanced)]
[Export ("initWithCoder:")]
public MyFileHandle (NSCoder coder) : base (NSObjectFlag.Empty)
{
//...
}
[Export ("initWithCoder:")]
[DesignatedInitializer]
[CompilerGenerated]
public MyFileHandle (NSCoder coder)
: base (NSObjectFlag.Empty)
{
//...
}
//...
}
How can I prevent binding library from generating constructors twice thus get rid of the error?
It seems that you can simply remove duplicated Constructor from ApiDefinitions.cs as #SushiHangover suggested.

NSWindowController in Swift. Subclassing and initializing with Nib

In a test Swift project, I am subclassing NSWindowController. My NSWindowController subclass is designed to work with a particular Nib file. It is desirable, then, that when my window controller is initialized, the nib file is automatically loaded by the window controller instance. In Objective-C, this was achieved by doing:
#implementation MyWindowController
- (id)init {
self = [super initWithWindowNibName:"MyWindowNib"]
if (self) {
// whatever
}
return self
}
#end
Now, in Swift this is not possible: init() cannot call super.init(windowNibName:), because the later is declared not as a designated initializer, but as a convenience one by NSWindowController.
How can this be done in Swift? I don't see a strightforward way of doing it.
P.S.: I have seen other questions regarding this topic, but, as long as I've been able to understand, the solutions all point to initialize the Window Controller by calling init(windowNibName:). Please note that this is not the desired beheaviour. The Window Controller should be initialized with init(), and it should be the Window Controller itself who "picks up" its Nib file and loads it.
If you use the init() just to call super.init(windowNibName:), you could instead just override the windowNibName variable.
override var windowNibName: String {
get {
return "MyWindowNib"
}
}
Then there should be no need to mess with the initializers.
You can create your own convenience initializer instead:
override convenience init() {
self.init(windowNibName: "MyWindowNib")
}
You should instead opt in to replacing all designated initializers in your subclass, simply delegating to super where appropriate. Confer https://stackoverflow.com/a/24220904/1460929

Hook in CLLocationManagerDelegate protocol

I have a problem from 3 days :( I want to hook in CLLocationManagerDelegate protocol this method:
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
I tried everything but without success. I know how to hook into class or framework but I can't find a solution to hook a Delegate.
Please help me!
Thanks
Hooking requires you to provide objective-C class you would like to hook. This is what Class type is for. One way to get obj-c class is by name via objc_getClass function. But in your case as I understand it correctly you don't have the name. You want to hook every class that conforms to CLLocationManagerDelegate protocol and implements specific method. Here is what you can do.
You can obtain every registered obj-C class and search for those which conform toCLLocationManagerDelegate protocol like this:
static IMP original_didUpdateLocations;
void replaced_didUpdateLocations(id self, SEL _cmd, CLLocationManager* manager, NSArray* locations)
{
NSLog(#"%# did update locations to %#", manager, locations);
original_didUpdateLocations(self, _cmd, manager, locations);
}
...
#import <objc/runtime.h>
int numClasses = objc_getClassList(NULL, 0);
Class* list = (Class*)malloc(sizeof(Class) * numClasses);
objc_getClassList(list, numClasses);
for (int i = 0; i < numClasses; i++)
{
if (class_conformsToProtocol(list[i], #protocol(CLLocationManagerDelegate)) &&
class_getInstanceMethod(list[i], #selector(locationManager:didUpdateLocations:)))
{
MSHookMessageEx(list[i], #selector(locationManager:didUpdateLocations:), (IMP)replaced_didUpdateLocations, (IMP*)&original_didUpdateLocations);
}
}
free(list);
We need to know how many classes there is. objc_getClassList(NULL, 0) returns number of all registered classes.
Allocating memory with malloc(sizeof(Class) * numClasses) and filling it with objects of type Class using objc_getClassList(list, numClasses).
Searching through all these classes for those which conform to CLLocationManagerDelegate protocol and implement locationManager:didUpdateLocations: method. If we found one we are hooking it with our own implementation.
In our own implementation we are printing some debug message and calling original implementation before returning. Of course, you can do whatever you what, this is just an example.
Freeing allocated memory using free(list).

How to bind a control to a singleton in Cocoa?

I have a singleton in my FTP app designed to store all of the types of servers that the app can handle, such as FTP or Amazon S3. These types are plugins which are located in the app bundle. Their path is located by applicationWillFinishLoading: and sent to the addServerType: method inside the singleton to be loaded and stored in an NSMutableDictionary.
My question is this:
How do I bind an NSDictionaryController to the dictionary inside the singleton instance? Can it be done in IB, or do I have to do it in code? I need to be able to display the dictionary's keys in an NSPopupButton so the user can select a server type.
Thanks in advance!
SphereCat1
I found / made up the answer to this: I simply override the init method so when it's called from the XIB file, it still returns the singleton. I then provide a method named realInit to do an actual initialization the first time init is called.
Code:
-(id)init
{
#synchronized(self)
{
if (_sharedInstance == nil)
{
_sharedInstance = [[VayprServerTypes alloc] realInit];
}
}
[self release];
return _sharedInstance;
}
-(id)realInit
{
if (self = [super init])
{
serverTypesArray = [[NSMutableArray alloc] init];
}
return self;
}
EDIT: Of course you'll need to define _sharedInstance as a static variable at the top of your class implementation:
static ClassTypeGoesHere *_sharedInstance;
ALSO EDIT: Since you now know for sure that your init method will be called at least once, you can go ahead and replace your normal singleton sharedInstance method with this:
+(ClassTypeGoesHere *)sharedInstance
{
return _sharedInstance;
}
If anyone sees any obvious problems with this design, please let me know!
SphereCat1

How to declare a function in Cocoa after the function using it?

I'm slowly building my application to a working state.
I'm using two functions called setCollection and addToCollection. These functions both accept NSArray as input.
I also have a function called add in which I use both of these functions. When I try to compile, Xcode shows an error:
'setCollection' undeclared (first use in this function)
I guess this has to do with the function called being defined below the active function. Another guess would be that the functions should be globalized to be useable inside my add function.
I'm normally a php coder. the way Php handles this is the first one. The functions called should be before the functions using them, because otherwise they just don't exist. Is there a way to make functions still to come available at runtime, or should I rearrange all functions to make them function properly?
You can declare functions ahead of time as follows:
void setCollection(NSArray * array);
void addToCollection(NSArray * array);
//...
// code that calls setCollection or addToCollection
//...
void setCollection(NSArray * array)
{
// your code here
}
void addToCollection(NSArray * array)
{
// your code here
}
If you are creating a custom class, and these are member functions (usually called methods in Objective-C) then you would declare the methods in your class header and define them in your class source file:
//MyClass.h:
#interface MyClass : NSObject
{
}
- (void)setCollection:(NSArray *)array;
- (void)addToCollection:(NSArray *)array;
#end
//MyClass.m:
#import "MyClass.h"
#implementation MyClass
- (void)setCollection:(NSArray *)array
{
// your code here
}
- (void)addToCollection:(NSArray *)array
{
// your code here
}
#end
//some other source file
#import "MyClass.h"
//...
MyClass * collection = [[MyClass alloc] init];
[collection setCollection:someArray];
[collection addToCollection:someArray];
//...
If your functions are global (not part of a class), you just have to put the declaration before the use, just like eJames suggests.
If your functions actually are methods (part of a class), you have to declare an anonymous category of your class before the implementation and put your method declarations in this interface:
#interface Myclass()
- (void) setCollection:(NSArray*)array;
- (void) addToCollection:(NSArray*)array;
#end
#implementation Myclass
// Code that calls setCollection or addToCollection
- (void) setCollection:(NSArray*)array
{
// your code here
}
- (void) addToCollection:(NSArray*)array
{
// your code here
}
#end
This way, you don't need to expose your functions in the main interface of MyClass.

Resources