Consider this code example:
class SomeArbitrarilyNamedClassPlusPlus {
public:
SomeArbitrarilyNamedClassPlusPlus(NSObject *object) { object_ = object; }
SomeArbitrarilyNamedClassPlusPlus() { object_ = nil; }
private:
NSObject *object_;
};
#interface SomeArbitrarilyNamedClassObjective : NSObject
{
SomeArbitrarilyNamedClassPlusPlus *_plusPlusObject;
}
#end
#implementation SomeArbitrarilyNamedClassObjective
-(id)init
{
if ((self = [super init]))
{
_plusPlusObject = new SomeArbitrarilyNamedClassPlusPlus(self);
}
return self;
}
-(void)dealloc
{
NSLog(#"deallocated");
delete _plusPlusObject;
}
#end
int main(int argc, const char * argv[])
{
{
SomeArbitrarilyNamedClassObjective *object = [[SomeArbitrarilyNamedClassObjective alloc] init];
}
return 0;
}
The object variable never gets deallocated. You can check it with Instruments - additional retain counter increment happens inside the -(id)init call.
I would never expect that attributes in C++ classes are strong and this makes me wondering - is there a way to make c++ attributes pointing on Objective-C objects weak?
UPDATE:
There is a way to avoid this using pointers to void in C++ class instead of NSObject* and initialize C++ class in -(id)init method like that:
...
_plusPlusObject = new SomeArbitrarilyNamedClassPlusPlus((__bridge void*)self);
...
However, the question still remains - is there a way to save Objective-C types inside C++ classes but make them weak?
Well, the answer turned out to be quite straightforward - use __weak attribute in C++ class:
class SomeArbitrarilyNamedClassPlusPlus {
public:
SomeArbitrarilyNamedClassPlusPlus(NSObject* object) { object_ = object; }
SomeArbitrarilyNamedClassPlusPlus() { object_ = nil; }
private:
__weak NSObject* object_;
};
Related
As a foray into new programming languages, I build well known data structures to familiarize myself with the syntax and the basic ins & outs of the language. In this case, I examine the stack in Objective-C. From Apple's Working with Objects we read about the keyword 'id'
...This is a special keyword used in Objective-C to mean “some kind of object.” It is a pointer to an object, like (NSObject *), but is special in that it doesn’t use an asterisk.
By using the keyword 'id', it seems possible to create a stack data structure that holds differing types of Obj-C objects; however, I am not sure if this as intended. Is it better to create the various class methods for each potential data type rather than attempting a generic method and make sure each stack adheres to a single Object type?. Here is what I have so far
XYZNode.h
#import <Foundation/Foundation.h>
#interface XYZNode : NSObject
#property id value;
#property XYZNode *next;
-(instancetype)initWithValue:(id)aValue next:(XYZNode *)aNext;
-(instancetype)init;
// Class factory methods should always start with the name of
// the class (without the prefix) that they create, with the
// exception of subclasses of classes with existing factory methods.
+(XYZNode *)nodeWithValue:(id)aValue nextNode:(XYZNode *)aNext;
#end
XYZNode.m
#import "XYZNode.h"
#implementation XYZNode
-(instancetype)initWithValue:(id)aValue next:(XYZNode *)aNext {
if (self = [super init]) {
_value = aValue;
_next = aNext;
} return self;
}
-(instancetype)init {
return [self initWithValue:nil next:nil];
}
+(XYZNode *)nodeWithValue:(id)aValue nextNode:(XYZNode *)aNext {
return [[self alloc] initWithValue:aValue next:aNext];
}
#end
XYZStack.h
#import <Foundation/Foundation.h>
#interface XYZStack : NSObject
-(void)pushValue:(id)aValue;
-(id)popValue;
-(BOOL)isEmpty;
-(instancetype)init;
-(instancetype)initWithValue:(id)aValue;
+(XYZStack *)stackWithValue:(id)aValue;
#end
XYZStack.m
#import "XYZStack.h"
#import "XYZNode.h"
// The extension hides how the values are stored
#interface XYZStack ()
#property XYZNode *lastNodeAdded;
#end
#implementation XYZStack
// Default initializer
-(instancetype)initWithValue:(id)aValue {
if (self = [super init]) {
_lastNodeAdded = nil;
}
if (aValue) {
[self pushValue:aValue];
}
return self;
}
// Call default initializer
-(instancetype)init{
return [self initWithValue:nil];
}
-(BOOL)isEmpty{
return ([self lastNodeAdded] == nil);
}
-(void)pushValue:(id)aValue {
[self setLastNodeAdded:[XYZNode nodeWithValue:aValue nextNode:[self lastNodeAdded]]];
}
-(id)popValue {
id temp = [[self lastNodeAdded] value];
[self setLastNodeAdded:[[self lastNodeAdded] next]];
return temp;
}
+(XYZStack *)stackWithValue:(id)aValue {
return [[self alloc] initWithValue:aValue];
}
#end
Any comments would be appreciated.
I'm trying to get a better grip on the Factory Pattern as illustrated here:
http://www.oodesign.com/factory-pattern.html
The examples are in Java, and I'm not a very strong Java programmer. I mostly don't understand the Constructor product ... = cClass... String.class line. I think I've got the "concept," but are these two code blocks analogous?
Furthermore, is there an example in Cocoa Foundation that uses this pattern? The only one I can think of is in UIKit registering cell classes against a UITableView.
Java:
class ProductFactory
{
private HashMap m_RegisteredProducts = new HashMap();
public void registerProduct (String productID, Class productClass)
{
m_RegisteredProducts.put(productID, productClass);
}
public Product createProduct(String productID)
{
Class productClass = (Class)m_RegisteredProducts.get(productID);
Constructor productConstructor = cClass.getDeclaredConstructor(new Class[] { String.class });
return (Product)productConstructor.newInstance(new Object[] { });
}
}
Objective-C:
#interface ProductFactory : NSObject
- (void)registerProduct:(Class)productClass withIdentifier:(NSString *)identifier;
- (id)newProductForIdentifier:(NSString *)identifier;
#end
#interface ProductFactory();
#property (strong, nonatomic) NSMutableDictionary *registeredProducts;
#end
#implementation ProductFactory
- (id)init
{
self = [super init];
if (self) {
_registeredProducts = [NSMutableDictionary dictionary];
}
return self;
}
- (void)registerProduct:(Class)productClass withIdentifier:(NSString *)identifier
{
self.registeredProducts[identifier] = NSStringFromClass(productClass);
}
- (id)newProductForIdentifier:(NSString *)identifier
{
NSString *classString = self.registeredProducts[identifier];
Class productClass = NSClassFromString(classString);
return [[productClass alloc] init];
}
#end
Yes, that is generally analogous. I haven't done java for a little while so I can't explicitly explain the Constructor line but it's kind of like the definition of a designated initialiser and how to find it.
You could do a little work with #protocols to allow a range of init methods to be available for the instantiation and interrogate the class to see which protocol it conforms to (using conformsToProtocol:).
Does anyone know if there is a way to set a property like a string in the User Defined Runtime Atributes sections of Interface Builder without creating a subclass of said component? For example, I want to store a metadata value for each component in my interface that I use later. I just don't want to have to create a subclass or each component to add a metadata property.
This is one approach I came up with. Opinions?
#import <UIKit/UIKit.h>
#import <objc/runtime.h>
#interface UIControl(MetaData)
#property (nonatomic, retain) id entityProperty;
#end
#implementation UIControl(MetaData)
static char const * const EntityPropertyKey = "EntityProperty";
#dynamic entityProperty;
- (id)entityProperty {
return objc_getAssociatedObject(self, EntityPropertyKey);
}
- (void)setEntityProperty:(id)newEntityProperty {
objc_setAssociatedObject(self, EntityPropertyKey, newEntityProperty, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#end
...
if (textField.entityProperty)
[managedObject setValue: textField.text forKey:textField.entityProperty];
You could keep an NSDictionary somewhere, perhaps in a singleton object that has methods for issuing unique ids for objects and storing metadata by the id keys in the dictionary. The UI objects have a tag property that you can use, if your ids are just incremented integers. Then the dictionary keys would just be NSNumbers for those unique integers.
Like this:
#import <Foundation/Foundation.h>
#interface ACLMetadataManager : NSArray
+(ACLMetadataManager*) sharedMetadataManager;
-(NSUInteger) getUniqueId;
-(void) setObject: (id) object forId:(NSUInteger) theId;
-(id) objectForId:(NSUInteger) theId;
#end
And:
#import "ACLMetadataManager.h"
#implementation ACLMetadataManager { // Private variables
NSMutableDictionary *_metadata;
NSUInteger _ids;
}
- (id)init {
self = [super init];
if (self) {
_metadata = [[NSMutableDictionary alloc] init];
}
return self;
}
+(ACLMetadataManager*) sharedMetadataManager { // Singleton getter
static ACLMetadataManager *instance;
if (instance != nil) {
return instance;
}
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0
static dispatch_once_t oneTimeThread;
dispatch_once(&oneTimeThread, ^(void) {
instance = [[ACLMetadataManager alloc] init];
});
#else
#synchronized(self) {
instance = [[ACLMetadataManager alloc] init];
}
#endif
return instance;
}
-(NSUInteger) getUniqueId { // Increment unique id when getter is called.
return ++_ids; // Start from 1 because tag is 0 by default.
}
-(void) setObject: (id) object forId:(NSUInteger) theId {
[_metadata setObject:object forKey:[NSNumber numberWithInteger:theId]];
}
-(id) objectForId:(NSUInteger) theId {
return [_metadata objectForKey:[NSNumber numberWithInteger:theId]];
}
// Override some methods to ensure singleton stays instantiated.
- (id) retain {
return self;
}
- (oneway void) release {
// Does nothing here.
}
- (id) autorelease {
return self;
}
- (NSUInteger) retainCount {
return INT32_MAX;
}
#end
Usage:
ACLMetadataManager *metadataManager = [ACLMetadataManager sharedMetadataManager];
myControl.tag = [metadataManager getUniqueId];
[metadataManager setObject:myMetadata forId:myControl.tag];
I've read several of the previous discussion about the subject but since I'm relatively new to Objective-C, I don't really understand them. (Blocks, selectors, and delegate are very new to me).
Here is the situation:
I'm using those abstract class RtMidi that are written in c++
void MidiInApi :: setCallback( RtMidiIn::RtMidiCallback callback, void *userData )
{
if ( inputData_.usingCallback ) {
errorString_ = "MidiInApi::setCallback: a callback function is already set!";
RtMidi::error( RtError::WARNING, errorString_ );
return;
}
if ( !callback ) {
errorString_ = "RtMidiIn::setCallback: callback function value is invalid!";
RtMidi::error( RtError::WARNING, errorString_ );
return;
}
inputData_.userCallback = (void *) callback;
inputData_.userData = userData;
inputData_.usingCallback = true;
}
I also have a class that Reciever that implements that callback (rtMidiCallback).
And at some point in my main file I need to write something like this
midiIn->setCallback(rtMidiCallback);
This Would be in a c++ context but in Objective-C I have no idea how to do it.
If you have any ideas, pointers I would be glad to discuss about it with you. Thank you very much
Best,
greg.
It's possible to have C++ and Objective-C within the same project and even within the same file (Objective-C++ with file extension .mm). If the code you're using is designed for a C++ callback, it may be easier to provide that and communicate between different object types outside of that mechanism.
// CPPClass.h
#ifndef CPPClass_h
#define CPPClass_h
class CPPClass {
private:
id m_ocObject;
public:
CPPClass(id ocObject);
virtual ~CPPClass();
void verifyCPP();
};
#endif
// OCClass.h
#import <Foundation/Foundation.h>
class CPPClass;
#interface OCClass : NSObject {
CPPClass *cppObject;
}
- (void)ocCallback;
- (void)verifyOC;
#end
// OCClass.mm
#import "OCClass.h"
#import "CPPClass.h"
#include <iostream>
#implementation OCClass
- (id)init {
self = [super init];
if (self) {
cppObject = new CPPClass(self);
}
return self;
}
- (void)dealloc {
delete cppObject;
}
- (void)ocCallback {
NSLog(#"Objective-C called from C++");
}
- (void)verifyOC {
NSLog(#"Objective-C called from Objective-C");
cppObject->verifyCPP();
}
#end
CPPClass::CPPClass(id ocObject) : m_ocObject(ocObject)
{}
CPPClass::~CPPClass() {}
void CPPClass::verifyCPP() {
std::cout << "C++ called from Objective-C" << std::endl;
[m_ocObject ocCallback];
}
To activate this, some other .mm file would have:
#import "OCClass.h"
...
OCClass *test = [[OCClass alloc] init];
[test verifyOC];
In Objective-C, it is possible to pass a class as a parameter to a method:
- (void) methodThatTakesClass:(Class)theClass;
And it is possible to pass an instance that is conforming to a protocol as a parameter:
- (void) myConformInstance:(id <MyProtocol>)theObject;
Is it possible to use the combined functionality? A method which takes a class which is conforming to a certain protocol.
Yes. The following is a valid program which will log the NSObject class.
#import <Foundation/Foundation.h>
void f(Class <NSObject> c) {
NSLog(#"%#",c);
}
int main() {
f([NSObject class]);
}
This would cause a compiler error if you tried to pass a class which doesn't conform to NSObject, such as the Object class. You can also use it for methods.
- (void)printClass:(Class <NSObject>)c;
also valid:
#interface Something: Object {
}
- (void) foo:(int(*)(void))bar;
#end
#implementation Something
- (void) foo:(int(*)(void))bar {
return (*bar)();
}
#end
int someFunc( void ) {
return 9;
}
int main ( int argc, char **argv ) {
Something *object = [[Something alloc] init];
printf( "%i\n", [object foo:&someFunc] );
[object release];
return 0;
}