Skip to content

Instantly share code, notes, and snippets.

@dodikk
Last active October 4, 2018 08:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dodikk/4a0f1d98faa7c1336551 to your computer and use it in GitHub Desktop.
Save dodikk/4a0f1d98faa7c1336551 to your computer and use it in GitHub Desktop.
Objective-C++ cast templates
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segueId isEqualToString:@"seagueAppointmentListToMap"])
{
HLJAppointment* appointment = objc_kind_of_cast<HLJAppointment>(sender);
HLJAppointmentMapController *controller = objc_member_of_cast<HLJAppointmentMapController>(destinationController);
// property injection
controller.model = appointment;
}
}
#define KINDOF_CAST(arg) ((__kindof typeof(arg))(arg))
// USAGE :
//
//
void example()
{
UICollectionViewFlowLayout* flowLayout = KINDOF_CAST(self.collectionView.collectionViewLayout);
}
// reasoning
//
// The macro works at compile time
// it relies on the `collectionViewLayout` declaration type
// so the expression results in
//
// UICollectionViewFlowLayout* flowLayout = (__kindof UICollectionViewLayout)(self.collectionView.collectionViewLayout);
// The `__kindof UICollectionViewLayout` type silences the compiler's "type mismatch" warnings
// because `UICollectionViewFlowLayout` is a child of `UICollectionViewLayout`
//
// At runtime it's better to use one of the templates above
//
#ifndef __JFF_CAST_FUNCTIONS_H__
#define __JFF_CAST_FUNCTIONS_H__
#import <Foundation/Foundation.h>
template < class DESTINATION >
DESTINATION* objc_kind_of_cast(id nsObject)
{
if (nil == nsObject) {
return nil;
}
Class destinationClass = [DESTINATION class];
if (![nsObject isKindOfClass:destinationClass]) {
return nil;
}
return (DESTINATION *)nsObject;
}
template < class DESTINATION >
DESTINATION* objc_member_of_cast(id nsObject)
{
if (nil == nsObject) {
return nil;
}
Class destinationClass = [DESTINATION class];
if (![nsObject isMemberOfClass:destinationClass]) {
return nil;
}
return (DESTINATION*)nsObject;
}
template < class DESTINATION >
DESTINATION* objc_dynamic_cast(id nsObject)
{
return objc_kind_of_cast<DESTINATION>(nsObject);
}
template < class DESTINATION >
DESTINATION *objc_reinterpret_cast(id nsObject)
{
return (DESTINATION *)nsObject;
}
#endif //__JFF_CAST_FUNCTIONS_H__
@dodikk
Copy link
Author

dodikk commented Oct 3, 2018

TODO: add a modern macro with typeof and kindof

By Scherbinin Anatoly from the cocoa chat ("Какао-чат: Cocoa, Xcode, objective C")

#define KINDOF_CAST(arg) ((__kindof typeof(arg))(arg))

@dodikk
Copy link
Author

dodikk commented Oct 3, 2018

Reasoning behind the macro

#define KINDOF_CAST(arg) ((__kindof typeof(arg))(arg))
UICollectionViewFlowLayout* flowLayout = KINDOF_CAST(self.collectionView.collectionViewLayout);

The macro works at compile time. It relies on the collectionViewLayout property declaration type.
So the expression results in

UICollectionViewFlowLayout* flowLayout = (__kindof UICollectionViewLayout)(self.collectionView.collectionViewLayout);

The __kindof UICollectionViewLayout type silences the compiler's "type mismatch" warnings because UICollectionViewFlowLayout is a child of UICollectionViewLayout.

The templates above do the runtime checks so these casts might co-exist depending on the "safety" level chosen by the programmer.

@dodikk
Copy link
Author

dodikk commented Oct 4, 2018

A separate gist for the compile time __kindof based cast
https://gist.github.com/dodikk/16d4e7b4ef6cb0cf98cd2dac44e13003

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment