Thrift-1340: Add support of ARC to Objective-C
Client: Objective-c
Patch: Hirano Satoshi
Adds -objc-arc flag to compiler and if used removes the retain/release/autorelease from generated code
git-svn-id: https://svn.apache.org/repos/asf/thrift/trunk@1210732 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/src/generate/t_cocoa_generator.cc b/compiler/cpp/src/generate/t_cocoa_generator.cc
index 26537ac..14ed478 100644
--- a/compiler/cpp/src/generate/t_cocoa_generator.cc
+++ b/compiler/cpp/src/generate/t_cocoa_generator.cc
@@ -71,9 +71,8 @@
void generate_xception(t_struct* txception);
void generate_service (t_service* tservice);
- void print_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value);
- std::string render_const_value(std::string name, t_type* type, t_const_value* value,
- bool containerize_it=false);
+ void print_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value, bool defval=false, bool is_property=false);
+ std::string render_const_value(ofstream& out, t_type* type, t_const_value* value, bool containerize_it=false);
void generate_cocoa_struct(t_struct* tstruct, bool is_exception);
void generate_cocoa_struct_interface(std::ofstream& out, t_struct* tstruct, bool is_xception=false);
@@ -275,6 +274,7 @@
"#import <TApplicationException.h>\n" +
"#import <TProtocolUtil.h>\n" +
"#import <TProcessor.h>\n" +
+ "#import <TObjective-C.h>\n" +
"\n";
// Include other Thrift includes
@@ -379,7 +379,7 @@
f_impl_ <<
"static " << type_name(type) << " " << cocoa_prefix_ << name;
if (!type->is_container() && !type->is_struct()) {
- f_impl_ << " = " << render_const_value(name, type, (*c_iter)->get_value());
+ f_impl_ << " = " << render_const_value(f_impl_, type, (*c_iter)->get_value());
}
f_impl_ << ";" << endl;
}
@@ -394,10 +394,11 @@
for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
if ((*c_iter)->get_type()->is_container() ||
(*c_iter)->get_type()->is_struct()) {
- string name = (*c_iter)->get_name();
- f_impl_ << indent() << cocoa_prefix_ << name << " = " << render_const_value(name,
- (*c_iter)->get_type(),
- (*c_iter)->get_value());
+ print_const_value(f_impl_,
+ cocoa_prefix_+(*c_iter)->get_name(),
+ (*c_iter)->get_type(),
+ (*c_iter)->get_value(),
+ false, false);
f_impl_ << ";" << endl;
}
}
@@ -491,6 +492,9 @@
out << "#endif" << endl << endl;
}
+ // default initializer
+ out << indent() << "- (id) init;" << endl;
+
// initializer for all fields
if (!members.empty()) {
generate_cocoa_struct_initializer_signature(out, tstruct);
@@ -534,7 +538,6 @@
}
}
-
/**
* Generate getter and setter declarations for all fields, plus an
* IsSet getter.
@@ -546,9 +549,11 @@
const vector<t_field*>& members = tstruct->get_members();
vector<t_field*>::const_iterator m_iter;
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ out << indent() << "#if !__has_feature(objc_arc)" << endl;
out << indent() << "- (" << type_name((*m_iter)->get_type()) << ") " << decapitalize((*m_iter)->get_name()) << ";" << endl;
out << indent() << "- (void) set" << capitalize((*m_iter)->get_name()) <<
": (" << type_name((*m_iter)->get_type()) << ") " << (*m_iter)->get_name() << ";" << endl;
+ out << indent() << "#endif" << endl;
out << indent() << "- (BOOL) " << (*m_iter)->get_name() << "IsSet;" << endl << endl;
}
}
@@ -581,7 +586,7 @@
out << indent() << "__" << (*m_iter)->get_name() << " = ";
if (type_can_be_null(t))
{
- out << "[[decoder decodeObjectForKey: @\"" << (*m_iter)->get_name() << "\"] retain];" << endl;
+ out << "[[decoder decodeObjectForKey: @\"" << (*m_iter)->get_name() << "\"] retain_stub];" << endl;
}
else if (t->is_enum())
{
@@ -704,6 +709,9 @@
indent(out) <<
"@implementation " << cocoa_prefix_ << tstruct->get_name() << endl << endl;
+ const vector<t_field*>& members = tstruct->get_members();
+ vector<t_field*>::const_iterator m_iter;
+
// exceptions need to call the designated initializer on NSException
if (is_exception) {
out << indent() << "- (id) init" << endl;
@@ -711,10 +719,29 @@
out << indent() << "return [super initWithName: @\"" << tstruct->get_name() <<
"\" reason: @\"unknown\" userInfo: nil];" << endl;
scope_down(out);
- }
+ out << endl;
+ } else {
+ // struct
- const vector<t_field*>& members = tstruct->get_members();
- vector<t_field*>::const_iterator m_iter;
+ // default initializer
+ // setup instance variables with default values
+ indent(out) << "- (id) init" << endl;
+ scope_up(out);
+ indent(out) << "self = [super init];" << endl;
+ if (members.size() > 0) {
+ out << "#if TARGET_OS_IPHONE || (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)" << endl;
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ t_type* t = get_true_type((*m_iter)->get_type());
+ if ((*m_iter)->get_value() != NULL) {
+ print_const_value(out, "self."+(*m_iter)->get_name(), t, (*m_iter)->get_value(), false, true);
+ }
+ }
+ out << "#endif" << endl;
+ }
+ indent(out) << "return self;" << endl;
+ scope_down(out);
+ out << endl;
+ }
// initializer with all fields as params
if (!members.empty()) {
@@ -731,9 +758,9 @@
t_type* t = get_true_type((*m_iter)->get_type());
out << indent() << "__" << (*m_iter)->get_name() << " = ";
if (type_can_be_null(t)) {
- out << "[" << (*m_iter)->get_name() << " retain];" << endl;
+ out << "[" << (*m_iter)->get_name() << " retain_stub];" << endl;
} else {
- out << (*m_iter)->get_name() << ";" << endl;
+ out << (*m_iter)->get_name() << ";" << endl;
}
out << indent() << "__" << (*m_iter)->get_name() << "_isset = YES;" << endl;
}
@@ -756,11 +783,11 @@
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
t_type* t = get_true_type((*m_iter)->get_type());
if (type_can_be_null(t)) {
- indent(out) << "[__" << (*m_iter)->get_name() << " release];" << endl;
+ indent(out) << "[__" << (*m_iter)->get_name() << " release_stub];" << endl;
}
}
- out << indent() << "[super dealloc];" << endl;
+ out << indent() << "[super dealloc_stub];" << endl;
scope_down(out);
out << endl;
}
@@ -842,7 +869,7 @@
if (type_can_be_null((*f_iter)->get_type())) {
// deserialized strings are autorelease, so don't release them
if (!(get_true_type((*f_iter)->get_type())->is_string())) {
- indent(out) << "[fieldValue release];" << endl;
+ indent(out) << "[fieldValue release_stub];" << endl;
}
}
@@ -1038,7 +1065,7 @@
if (!type_can_be_null(type)) {
indent(out) << "return __" << field_name << ";" << endl;
} else {
- indent(out) << "return [[__" << field_name << " retain] autorelease];" << endl;
+ indent(out) << "return [[__" << field_name << " retain_stub] autorelease_stub];" << endl;
}
indent_down();
indent(out) << "}" << endl << endl;
@@ -1050,8 +1077,8 @@
if (!type_can_be_null(type)) {
indent(out) << "__" << field_name << " = " << field_name << ";" << endl;
} else {
- indent(out) << "[" << field_name << " retain];" << endl;
- indent(out) << "[__" << field_name << " release];" << endl;
+ indent(out) << "[" << field_name << " retain_stub];" << endl;
+ indent(out) << "[__" << field_name << " release_stub];" << endl;
indent(out) << "__" << field_name << " = " << field_name << ";" << endl;
}
indent(out) << "__" << field_name << "_isset = YES;" << endl;
@@ -1069,7 +1096,7 @@
indent(out) << "- (void) unset" << cap_name << " {" << endl;
indent_up();
if (type_can_be_null(type)) {
- indent(out) << "[__" << field_name << " release];" << endl;
+ indent(out) << "[__" << field_name << " release_stub];" << endl;
indent(out) << "__" << field_name << " = nil;" << endl;
}
indent(out) << "__" << field_name << "_isset = NO;" << endl;
@@ -1281,9 +1308,9 @@
out << "- (id) initWithInProtocol: (id <TProtocol>) anInProtocol outProtocol: (id <TProtocol>) anOutProtocol" << endl;
scope_up(out);
- out << indent() << "[super init];" << endl;
- out << indent() << "inProtocol = [anInProtocol retain];" << endl;
- out << indent() << "outProtocol = [anOutProtocol retain];" << endl;
+ out << indent() << "self = [super init];" << endl;
+ out << indent() << "inProtocol = [anInProtocol retain_stub];" << endl;
+ out << indent() << "outProtocol = [anOutProtocol retain_stub];" << endl;
out << indent() << "return self;" << endl;
scope_down(out);
out << endl;
@@ -1291,9 +1318,9 @@
// dealloc
out << "- (void) dealloc" << endl;
scope_up(out);
- out << indent() << "[inProtocol release];" << endl;
- out << indent() << "[outProtocol release];" << endl;
- out << indent() << "[super dealloc];" << endl;
+ out << indent() << "[inProtocol release_stub];" << endl;
+ out << indent() << "[outProtocol release_stub];" << endl;
+ out << indent() << "[super dealloc_stub];" << endl;
scope_down(out);
out << endl;
@@ -1387,7 +1414,7 @@
string resultname = function_result_helper_struct_type(*f_iter);
out <<
indent() << cocoa_prefix_ << resultname << " * result = [[[" << cocoa_prefix_ <<
- resultname << " alloc] init] autorelease];" << endl;
+ resultname << " alloc] init] autorelease_stub];" << endl;
indent(out) << "[result read: inProtocol];" << endl;
indent(out) << "[inProtocol readMessageEnd];" << endl;
@@ -1480,8 +1507,8 @@
out << indent() << "if (!self) {" << endl;
out << indent() << " return nil;" << endl;
out << indent() << "}" << endl;
- out << indent() << "mService = [service retain];" << endl;
- out << indent() << "mMethodMap = [[NSMutableDictionary dictionary] retain];" << endl;
+ out << indent() << "mService = [service retain_stub];" << endl;
+ out << indent() << "mMethodMap = [[NSMutableDictionary dictionary] retain_stub];" << endl;
// generate method map for routing incoming calls
vector<t_function*> functions = tservice->get_functions();
@@ -1505,7 +1532,7 @@
out << endl;
out << indent() << "- (id<"<<cocoa_prefix_ << tservice->get_name() << ">) service" << endl;
out << indent() << "{" << endl;
- out << indent() << " return [[mService retain] autorelease];" << endl;
+ out << indent() << " return [[mService retain_stub] autorelease_stub];" << endl;
out << indent() << "}" << endl;
// implementation of the TProcess method, which dispatches the incoming call using the method map
@@ -1588,8 +1615,8 @@
out << indent() << "[result write: outProtocol];" << endl;
out << indent() << "[outProtocol writeMessageEnd];" << endl;
out << indent() << "[[outProtocol transport] flush];" << endl;
- out << indent() << "[result release];" << endl;
- out << indent() << "[args release];" << endl;
+ out << indent() << "[result release_stub];" << endl;
+ out << indent() << "[args release_stub];" << endl;
scope_down(out);
}
@@ -1598,9 +1625,9 @@
out << endl;
out << "- (void) dealloc" << endl;
scope_up(out);
- out << indent() << "[mService release];" << endl;
- out << indent() << "[mMethodMap release];" << endl;
- out << indent() << "[super dealloc];" << endl;
+ out << indent() << "[mService release_stub];" << endl;
+ out << indent() << "[mMethodMap release_stub];" << endl;
+ out << indent() << "[super dealloc_stub];" << endl;
scope_down(out);
out << endl;
@@ -1816,13 +1843,13 @@
if (type_can_be_null(keyType)) {
if (!(get_true_type(keyType)->is_string())) {
- indent(out) << "[" << containerize(keyType, key) << " release];" << endl;
+ indent(out) << "[" << containerize(keyType, key) << " release_stub];" << endl;
}
}
if (type_can_be_null(valType)) {
if (!(get_true_type(valType)->is_string())) {
- indent(out) << "[" << containerize(valType, val) << " release];" << endl;
+ indent(out) << "[" << containerize(valType, val) << " release_stub];" << endl;
}
}
}
@@ -1845,7 +1872,7 @@
if (type_can_be_null(type)) {
// deserialized strings are autorelease, so don't release them
if (!(get_true_type(type)->is_string())) {
- indent(out) << "[" << containerize(type, elem) << " release];" << endl;
+ indent(out) << "[" << containerize(type, elem) << " release_stub];" << endl;
}
}
}
@@ -1867,7 +1894,7 @@
if (type_can_be_null(type)) {
if (!(get_true_type(type)->is_string())) {
- indent(out) << "[" << containerize(type, elem) << " release];" << endl;
+ indent(out) << "[" << containerize(type, elem) << " release_stub];" << endl;
}
}
}
@@ -2126,11 +2153,11 @@
} else if (ttype->is_enum()) {
return "int";
} else if (ttype->is_map()) {
- result = "NSDictionary";
+ result = "NSMutableDictionary";
} else if (ttype->is_set()) {
- result = "NSSet";
+ result = "NSMutableSet";
} else if (ttype->is_list()) {
- result = "NSArray";
+ result = "NSMutableArray";
} else {
// Check for prefix
t_program* program = ttype->get_program();
@@ -2181,8 +2208,152 @@
}
}
-
/**
+ * Prints the value of a constant with the given type. Note that type checking
+ * is NOT performed in this function as it is always run beforehand using the
+ * validate_types method in main.cc
+ */
+void t_cocoa_generator::print_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value, bool defval, bool is_property) {
+ type = get_true_type(type);
+
+ indent(out);
+ if (type->is_base_type()) {
+ string v2 = render_const_value(out, type, value);
+ if (defval)
+ out << type_name(type) << " ";
+ out << name << " = " << v2 << ";" << endl << endl;
+ } else if (type->is_enum()) {
+ if (defval)
+ out << type_name(type) << " ";
+ out << name << " = " << render_const_value(out, type, value) << ";" << endl << endl;
+ } else if (type->is_struct() || type->is_xception()) {
+ const vector<t_field*>& fields = ((t_struct*)type)->get_members();
+ vector<t_field*>::const_iterator f_iter;
+ const map<t_const_value*, t_const_value*>& val = value->get_map();
+ map<t_const_value*, t_const_value*>::const_iterator v_iter;
+ if (defval)
+ out << type_name(type) << " ";
+ if (defval || is_property)
+ out << name << " = [[[" << type_name(type, true) << " alloc] init] autorelease_stub];" << endl;
+ else
+ out << name << " = [[" << type_name(type, true) << " alloc] init];" << endl;
+ for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+ t_type* field_type = NULL;
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ if ((*f_iter)->get_name() == v_iter->first->get_string()) {
+ field_type = (*f_iter)->get_type();
+ }
+ }
+ if (field_type == NULL) {
+ throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
+ }
+ string val = render_const_value(out, field_type, v_iter->second);
+ std::string cap_name = capitalize(v_iter->first->get_string());
+ indent(out) << "[" << name << " set" << cap_name << ":" << val << "];" << endl;
+ }
+ out << endl;
+ } else if (type->is_map()) {
+ t_type* ktype = ((t_map*)type)->get_key_type();
+ t_type* vtype = ((t_map*)type)->get_val_type();
+ const map<t_const_value*, t_const_value*>& val = value->get_map();
+ map<t_const_value*, t_const_value*>::const_iterator v_iter;
+ if (defval)
+ out << "NSMutableDictionary *";
+ if (defval || is_property)
+ out << name << " = [[[NSMutableDictionary alloc] initWithCapacity:" << val.size() << "] autorelease_stub]; " << endl;
+ else
+ out << name << " = [[NSMutableDictionary alloc] initWithCapacity:" << val.size() << "]; " << endl;
+ for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+ string key = render_const_value(out, ktype, v_iter->first, true);
+ string val = render_const_value(out, vtype, v_iter->second, true);
+ indent(out) << "[" << name << " setObject:" << val << " forKey:" << key << "];" << endl;
+ }
+ out << endl;
+ } else if (type->is_list()) {
+ t_type* etype = ((t_list*)type)->get_elem_type();
+ const vector<t_const_value*>& val = value->get_list();
+ vector<t_const_value*>::const_iterator v_iter;
+ if (defval)
+ out << "NSMutableArray *";
+ if (defval || is_property)
+ out << name << " = [[[NSMutableArray alloc] initWithCapacity:" << val.size() <<"] autorelease_stub];" << endl;
+ else
+ out << name << " = [[NSMutableArray alloc] initWithCapacity:" << val.size() <<"];" << endl;
+ for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+ string val = render_const_value(out, etype, *v_iter, true);
+ indent(out) << "[" << name << " addObject:" << val << "];" << endl;
+ }
+ out << endl;
+ } else if (type->is_set()) {
+ t_type* etype = ((t_set*)type)->get_elem_type();
+ const vector<t_const_value*>& val = value->get_list();
+ vector<t_const_value*>::const_iterator v_iter;
+ if (defval)
+ out << "NSMutableSet *";
+ if (defval || is_property)
+ out << name << " = [[[NSMutableSet alloc] initWithCapacity:" << val.size() << "] autorelease_stub];" << endl;
+ else
+ out << name << " = [[NSMutableSet alloc] initWithCapacity:" << val.size() << "];" << endl;
+ for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+ string val = render_const_value(out, etype, *v_iter, true);
+ indent(out) << "[" << name << " addObject:" << val << "];" << endl;
+ }
+ out << endl;
+ } else {
+ throw "compiler error: no const of type " + type->get_name();
+ }
+}
+
+string t_cocoa_generator::render_const_value(ofstream& out, t_type* type, t_const_value* value, bool containerize_it) {
+ type = get_true_type(type);
+ std::ostringstream render;
+
+ if (type->is_base_type()) {
+ t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+ switch (tbase) {
+ case t_base_type::TYPE_STRING:
+ // We must handle binary constant but the syntax of IDL defines
+ // nothing about binary constant.
+ // if ((t_base_type*)type)->is_binary())
+ // // binary code
+ render << "@\"" << get_escaped_string(value) << '"';
+ break;
+ case t_base_type::TYPE_BOOL:
+ render << ((value->get_integer() > 0) ? "YES" : "NO");
+ break;
+ case t_base_type::TYPE_BYTE:
+ case t_base_type::TYPE_I16:
+ case t_base_type::TYPE_I32:
+ case t_base_type::TYPE_I64:
+ render << value->get_integer();
+ break;
+ case t_base_type::TYPE_DOUBLE:
+ if (value->get_type() == t_const_value::CV_INTEGER) {
+ render << value->get_integer();
+ } else {
+ render << value->get_double();
+ }
+ break;
+ default:
+ throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
+ }
+ } else if (type->is_enum()) {
+ render << value->get_integer();
+ } else {
+ string t = tmp("tmp");
+ print_const_value(out, t, type, value, true, false);
+ render << t;
+ }
+
+ if (containerize_it) {
+ return containerize(type, render.str());
+ }
+ return render.str();
+}
+
+#if 0
+/**
+ORIGINAL
* Spit out code that evaluates to the specified constant value.
*/
string t_cocoa_generator::render_const_value(string name,
@@ -2220,13 +2391,19 @@
} else if (type->is_enum()) {
render << value->get_integer();
} else if (type->is_struct() || type->is_xception()) {
- render << "[[" << type_name(type, true) << " alloc] initWith";
const vector<t_field*>& fields = ((t_struct*)type)->get_members();
vector<t_field*>::const_iterator f_iter;
const map<t_const_value*, t_const_value*>& val = value->get_map();
map<t_const_value*, t_const_value*>::const_iterator v_iter;
+ if (val.size() > 0)
+ render << "[[" << type_name(type, true) << " alloc] initWith";
+ else
+ render << "[[" << type_name(type, true) << " alloc] init";
bool first = true;
for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+ // FIXME The generated code does not match with initWithXXX
+ // initializer and causes compile error.
+ // Try: test/DebugProtoTest.thrift and test/SmallTest.thrift
t_type* field_type = NULL;
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
if ((*f_iter)->get_name() == v_iter->first->get_string()) {
@@ -2262,7 +2439,10 @@
}
render << val << ", " << key;
}
- render << ", nil]";
+ if (first)
+ render << " nil]";
+ else
+ render << ", nil]";
} else if (type->is_list()) {
render << "[[NSArray alloc] initWithObjects: ";
t_type * etype = ((t_list*)type)->get_elem_type();
@@ -2277,7 +2457,10 @@
}
render << render_const_value(name, etype, *v_iter, true);
}
- render << ", nil]";
+ if (first)
+ render << " nil]";
+ else
+ render << ", nil]";
} else if (type->is_set()) {
render << "[[NSSet alloc] initWithObjects: ";
t_type * etype = ((t_set*)type)->get_elem_type();
@@ -2292,7 +2475,10 @@
}
render << render_const_value(name, etype, *v_iter, true);
}
- render << ", nil]";
+ if (first)
+ render << " nil]";
+ else
+ render << ", nil]";
} else {
throw "don't know how to render constant for type: " + type->get_name();
}
@@ -2303,7 +2489,7 @@
return render.str();
}
-
+#endif
/**
* Declares a field.
diff --git a/lib/cocoa/src/TApplicationException.m b/lib/cocoa/src/TApplicationException.m
index 7068753..66c2f2b 100644
--- a/lib/cocoa/src/TApplicationException.m
+++ b/lib/cocoa/src/TApplicationException.m
@@ -19,6 +19,7 @@
#import "TApplicationException.h"
#import "TProtocolUtil.h"
+#import "TObjective-C.h"
@implementation TApplicationException
@@ -124,7 +125,7 @@
reason: (NSString *) reason
{
return [[[TApplicationException alloc] initWithType: type
- reason: reason] autorelease];
+ reason: reason] autorelease_stub];
}
@end
diff --git a/lib/cocoa/src/TException.m b/lib/cocoa/src/TException.m
index 7c84199..0160e3b 100644
--- a/lib/cocoa/src/TException.m
+++ b/lib/cocoa/src/TException.m
@@ -18,6 +18,7 @@
*/
#import "TException.h"
+#import "TObjective-C.h"
@implementation TException
diff --git a/lib/cocoa/src/TObjective-C.h b/lib/cocoa/src/TObjective-C.h
new file mode 100644
index 0000000..9c0831d
--- /dev/null
+++ b/lib/cocoa/src/TObjective-C.h
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * TObjective-C.h is for supporting coexistence of both the ARC (Automatic
+ * Reference Counting) mode and the Non-ARC mode of Objective-C
+ * in the same source code.
+ *
+ * 2011/11/14 HIRANO Satoshi (AIST, Japan)
+ *
+ * Before:
+ *
+ * var = [aObject retain];
+ * [aObject release];
+ * [aObject autorelease];
+ * [super dealloc];
+ * CFFunction(obj);
+ *
+ * ARC and Non-ARC compatible:
+ *
+ * #import "TObjective-C.h"
+ * var = [aObject retain_stub];
+ * [aObject release_stub];
+ * [aObject autorelease_stub];
+ * [super dealloc_stub];
+ * CFFunction(bridge_stub obj);
+ *
+ * Don't use retain_stub for @property(retain).
+ * Use NSAutoreleasePool like this:
+ * #if __has_feature(objc_arc)
+ * @autoreleasepool {
+ * // code
+ * }
+ * #else
+ * NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init...
+ * // code
+ * [pool release];
+ * #endif
+ */
+
+
+#if !defined(retain_stub)
+#if __has_feature(objc_arc)
+#define retain_stub self
+#define autorelease_stub self
+#define release_stub self
+#define dealloc_stub self
+#define bridge_stub __bridge
+#else
+#define retain_stub retain
+#define autorelease_stub autorelease
+#define release_stub release
+#define dealloc_stub dealloc
+#define bridge_stub
+#endif
+#endif
diff --git a/lib/cocoa/src/TSharedProcessorFactory.m b/lib/cocoa/src/TSharedProcessorFactory.m
index b38e73a..a0007c0 100644
--- a/lib/cocoa/src/TSharedProcessorFactory.m
+++ b/lib/cocoa/src/TSharedProcessorFactory.m
@@ -19,6 +19,7 @@
#import "TSharedProcessorFactory.h"
+#import "TObjective-C.h"
@implementation TSharedProcessorFactory
@@ -31,21 +32,21 @@
return nil;
}
- mSharedProcessor = [sharedProcessor retain];
+ mSharedProcessor = [sharedProcessor retain_stub];
return self;
}
- (void) dealloc
{
- [mSharedProcessor release];
- [super dealloc];
+ [mSharedProcessor release_stub];
+ [super dealloc_stub];
}
- (id<TProcessor>) processorForTransport: (id<TTransport>) transport
{
- return [[mSharedProcessor retain] autorelease];
+ return [[mSharedProcessor retain_stub] autorelease_stub];
}
@end
diff --git a/lib/cocoa/src/protocol/TBinaryProtocol.m b/lib/cocoa/src/protocol/TBinaryProtocol.m
index b272716..f269aaa 100644
--- a/lib/cocoa/src/protocol/TBinaryProtocol.m
+++ b/lib/cocoa/src/protocol/TBinaryProtocol.m
@@ -19,6 +19,7 @@
#import "TBinaryProtocol.h"
#import "TProtocolException.h"
+#import "TObjective-C.h"
int32_t VERSION_1 = 0x80010000;
int32_t VERSION_MASK = 0xffff0000;
@@ -56,7 +57,7 @@
strictWrite: (BOOL) strictWrite
{
self = [super init];
- mTransport = [transport retain];
+ mTransport = [transport retain_stub];
mStrictRead = strictRead;
mStrictWrite = strictWrite;
return self;
@@ -77,8 +78,8 @@
- (void) dealloc
{
- [mTransport release];
- [super dealloc];
+ [mTransport release_stub];
+ [super dealloc_stub];
}
diff --git a/lib/cocoa/src/server/TSocketServer.m b/lib/cocoa/src/server/TSocketServer.m
index 5f7fa3c..057f41f 100644
--- a/lib/cocoa/src/server/TSocketServer.m
+++ b/lib/cocoa/src/server/TSocketServer.m
@@ -22,6 +22,7 @@
#import "TNSFileHandleTransport.h"
#import "TProtocol.h"
#import "TTransportException.h"
+#import "TObjective-C.h"
#import <sys/socket.h>
#include <netinet/in.h>
@@ -40,9 +41,9 @@
{
self = [super init];
- mInputProtocolFactory = [protocolFactory retain];
- mOutputProtocolFactory = [protocolFactory retain];
- mProcessorFactory = [processorFactory retain];
+ mInputProtocolFactory = [protocolFactory retain_stub];
+ mOutputProtocolFactory = [protocolFactory retain_stub];
+ mProcessorFactory = [processorFactory retain_stub];
// create a socket.
int fd = -1;
@@ -60,7 +61,7 @@
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
NSData *address = [NSData dataWithBytes:&addr length:sizeof(addr)];
- if (CFSocketSetAddress(socket, (CFDataRef)address) != kCFSocketSuccess) {
+ if (CFSocketSetAddress(socket, (bridge_stub CFDataRef)address) != kCFSocketSuccess) {
CFSocketInvalidate(socket);
CFRelease(socket);
NSLog(@"*** Could not bind to address");
@@ -96,11 +97,11 @@
- (void) dealloc {
[[NSNotificationCenter defaultCenter] removeObject: self];
- [mInputProtocolFactory release];
- [mOutputProtocolFactory release];
- [mProcessorFactory release];
- [mSocketFileHandle release];
- [super dealloc];
+ [mInputProtocolFactory release_stub];
+ [mOutputProtocolFactory release_stub];
+ [mProcessorFactory release_stub];
+ [mSocketFileHandle release_stub];
+ [super dealloc_stub];
}
@@ -119,6 +120,38 @@
- (void) handleClientConnection: (NSFileHandle *) clientSocket
{
+#if __has_feature(objc_arc)
+ @autoreleasepool {
+ TNSFileHandleTransport * transport = [[TNSFileHandleTransport alloc] initWithFileHandle: clientSocket];
+ id<TProcessor> processor = [mProcessorFactory processorForTransport: transport];
+
+ id <TProtocol> inProtocol = [mInputProtocolFactory newProtocolOnTransport: transport];
+ id <TProtocol> outProtocol = [mOutputProtocolFactory newProtocolOnTransport: transport];
+
+ @try {
+ BOOL result = NO;
+ do {
+ @autoreleasepool {
+ result = [processor processOnInputProtocol: inProtocol outputProtocol: outProtocol];
+ }
+ } while (result);
+ }
+ @catch (TTransportException * te) {
+ //NSLog(@"Caught transport exception, abandoning client connection: %@", te);
+ }
+
+ NSNotification * n = [NSNotification notificationWithName: kTSocketServer_ClientConnectionFinishedForProcessorNotification
+ object: self
+ userInfo: [NSDictionary dictionaryWithObjectsAndKeys:
+ processor,
+ kTSocketServer_ProcessorKey,
+ transport,
+ kTSockerServer_TransportKey,
+ nil]];
+ [[NSNotificationCenter defaultCenter] performSelectorOnMainThread: @selector(postNotification:) withObject: n waitUntilDone: YES];
+
+ }
+#else
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
TNSFileHandleTransport * transport = [[TNSFileHandleTransport alloc] initWithFileHandle: clientSocket];
@@ -150,6 +183,7 @@
[[NSNotificationCenter defaultCenter] performSelectorOnMainThread: @selector(postNotification:) withObject: n waitUntilDone: YES];
[pool release];
+#endif
}
diff --git a/lib/cocoa/src/transport/THTTPClient.m b/lib/cocoa/src/transport/THTTPClient.m
index 1eaa859..5617d45 100644
--- a/lib/cocoa/src/transport/THTTPClient.m
+++ b/lib/cocoa/src/transport/THTTPClient.m
@@ -19,6 +19,7 @@
#import "THTTPClient.h"
#import "TTransportException.h"
+#import "TObjective-C.h"
@implementation THTTPClient
@@ -26,7 +27,7 @@
- (void) setupRequest
{
if (mRequest != nil) {
- [mRequest release];
+ [mRequest release_stub];
}
// set up our request object that we'll use for each request
@@ -67,9 +68,9 @@
mTimeout = timeout;
if (userAgent) {
- mUserAgent = [userAgent retain];
+ mUserAgent = [userAgent retain_stub];
}
- mURL = [aURL retain];
+ mURL = [aURL retain_stub];
[self setupRequest];
@@ -82,8 +83,8 @@
- (void) setURL: (NSURL *) aURL
{
- [aURL retain];
- [mURL release];
+ [aURL retain_stub];
+ [mURL release_stub];
mURL = aURL;
[self setupRequest];
@@ -92,12 +93,12 @@
- (void) dealloc
{
- [mURL release];
- [mUserAgent release];
- [mRequest release];
- [mRequestData release];
- [mResponseData release];
- [super dealloc];
+ [mURL release_stub];
+ [mUserAgent release_stub];
+ [mRequest release_stub];
+ [mRequestData release_stub];
+ [mResponseData release_stub];
+ [super dealloc_stub];
}
@@ -151,8 +152,8 @@
}
// phew!
- [mResponseData release];
- mResponseData = [responseData retain];
+ [mResponseData release_stub];
+ mResponseData = [responseData retain_stub];
mResponseDataOffset = 0;
}
diff --git a/lib/cocoa/src/transport/TMemoryBuffer.m b/lib/cocoa/src/transport/TMemoryBuffer.m
index 869010a..c3801c7 100644
--- a/lib/cocoa/src/transport/TMemoryBuffer.m
+++ b/lib/cocoa/src/transport/TMemoryBuffer.m
@@ -19,6 +19,7 @@
#import "TMemoryBuffer.h"
#import "TTransportException.h"
+#import "TObjective-C.h"
#define GARBAGE_BUFFER_SIZE 4096 // 4KiB
@@ -61,11 +62,11 @@
}
- (NSData *)getBuffer {
- return [[mBuffer copy] autorelease];
+ return [[mBuffer copy] autorelease_stub];
}
- (void)dealloc {
- [mBuffer release];
- [super dealloc];
+ [mBuffer release_stub];
+ [super dealloc_stub];
}
@end
diff --git a/lib/cocoa/src/transport/TNSFileHandleTransport.m b/lib/cocoa/src/transport/TNSFileHandleTransport.m
index b218218..0ff200b 100644
--- a/lib/cocoa/src/transport/TNSFileHandleTransport.m
+++ b/lib/cocoa/src/transport/TNSFileHandleTransport.m
@@ -20,6 +20,7 @@
#import "TNSFileHandleTransport.h"
#import "TTransportException.h"
+#import "TObjective-C.h"
@implementation TNSFileHandleTransport
@@ -36,17 +37,17 @@
{
self = [super init];
- mInputFileHandle = [inputFileHandle retain];
- mOutputFileHandle = [outputFileHandle retain];
+ mInputFileHandle = [inputFileHandle retain_stub];
+ mOutputFileHandle = [outputFileHandle retain_stub];
return self;
}
- (void) dealloc {
- [mInputFileHandle release];
- [mOutputFileHandle release];
- [super dealloc];
+ [mInputFileHandle release_stub];
+ [mOutputFileHandle release_stub];
+ [super dealloc_stub];
}
@@ -66,9 +67,10 @@
}
-- (void) write: (uint8_t *) data offset: (unsigned int) offset length: (unsigned int) length
+- (void) write: (const uint8_t *) data offset: (unsigned int) offset length: (unsigned int) length
{
- NSData * dataObject = [[NSData alloc] initWithBytesNoCopy: data+offset
+ void *pos = (void *) data + offset;
+ NSData * dataObject = [[NSData alloc] initWithBytesNoCopy: pos // data+offset
length: length
freeWhenDone: NO];
@@ -79,7 +81,7 @@
reason: [NSString stringWithFormat: @"%s: Unable to write data: %@", __PRETTY_FUNCTION__, e]];
}
- [dataObject release];
+ [dataObject release_stub];
}
diff --git a/lib/cocoa/src/transport/TNSStreamTransport.m b/lib/cocoa/src/transport/TNSStreamTransport.m
index 1d4cfee..265e0ba 100644
--- a/lib/cocoa/src/transport/TNSStreamTransport.m
+++ b/lib/cocoa/src/transport/TNSStreamTransport.m
@@ -19,6 +19,7 @@
#import "TNSStreamTransport.h"
#import "TTransportException.h"
+#import "TObjective-C.h"
@implementation TNSStreamTransport
@@ -26,9 +27,9 @@
- (id) initWithInputStream: (NSInputStream *) input
outputStream: (NSOutputStream *) output
{
- [super init];
- mInput = [input retain];
- mOutput = [output retain];
+ self = [super init];
+ mInput = [input retain_stub];
+ mOutput = [output retain_stub];
return self;
}
@@ -44,9 +45,9 @@
- (void) dealloc
{
- [mInput release];
- [mOutput release];
- [super dealloc];
+ [mInput release_stub];
+ [mOutput release_stub];
+ [super dealloc_stub];
}
@@ -65,7 +66,7 @@
}
-- (void) write: (uint8_t *) data offset: (unsigned int) offset length: (unsigned int) length
+- (void) write: (const uint8_t *) data offset: (unsigned int) offset length: (unsigned int) length
{
int got = 0;
int result = 0;
diff --git a/lib/cocoa/src/transport/TSocketClient.h b/lib/cocoa/src/transport/TSocketClient.h
index 0ea957d..372850f 100644
--- a/lib/cocoa/src/transport/TSocketClient.h
+++ b/lib/cocoa/src/transport/TSocketClient.h
@@ -20,7 +20,11 @@
#import <Foundation/Foundation.h>
#import "TNSStreamTransport.h"
-@interface TSocketClient : TNSStreamTransport {
+@interface TSocketClient : TNSStreamTransport
+#if TARGET_OS_IPHONE || (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
+<NSStreamDelegate>
+#endif
+{
}
- (id) initWithHostname: (NSString *) hostname
diff --git a/lib/cocoa/src/transport/TSocketClient.m b/lib/cocoa/src/transport/TSocketClient.m
index 74d4af9..256ecf3 100644
--- a/lib/cocoa/src/transport/TSocketClient.m
+++ b/lib/cocoa/src/transport/TSocketClient.m
@@ -17,6 +17,7 @@
* under the License.
*/
#import "TSocketClient.h"
+#import "TObjective-C.h"
#if !TARGET_OS_IPHONE
#import <CoreServices/CoreServices.h>
@@ -33,22 +34,24 @@
NSOutputStream * outputStream = NULL;
CFReadStreamRef readStream = NULL;
CFWriteStreamRef writeStream = NULL;
- CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (CFStringRef)hostname, port, &readStream, &writeStream);
+ CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (bridge_stub CFStringRef)hostname, port, &readStream, &writeStream);
if (readStream && writeStream) {
CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
- inputStream = (NSInputStream *)readStream;
- [inputStream retain];
+ inputStream = (bridge_stub NSInputStream *)readStream;
+ [inputStream retain_stub];
[inputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
- outputStream = (NSOutputStream *)writeStream;
- [outputStream retain];
+ outputStream = (bridge_stub NSOutputStream *)writeStream;
+ [outputStream retain_stub];
[outputStream setDelegate:self];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream open];
+ CFRelease(readStream);
+ CFRelease(writeStream);
}
self = [super initWithInputStream: inputStream outputStream: outputStream];
diff --git a/lib/cocoa/src/transport/TTransportException.m b/lib/cocoa/src/transport/TTransportException.m
index aa67149..43cdfbd 100644
--- a/lib/cocoa/src/transport/TTransportException.m
+++ b/lib/cocoa/src/transport/TTransportException.m
@@ -18,6 +18,7 @@
*/
#import "TTransportException.h"
+#import "TObjective-C.h"
@implementation TTransportException
diff --git a/test/ThriftTest.thrift b/test/ThriftTest.thrift
index 6918584..633be1f 100644
--- a/test/ThriftTest.thrift
+++ b/test/ThriftTest.thrift
@@ -34,6 +34,7 @@
namespace go ThriftTest
namespace php ThriftTest
namespace delphi Thrift.Test
+namespace cocoa ThriftTest
namespace * thrift.test
/**