In an ARC enabled project I am trying to store an allocated NSTimer inside a C++ wrapper (the NSTimer instance is not initialized):
#ifndef Wrapper_h
#define Wrapper_h
class Wrapper {
public:
Wrapper(id data): data_(data) { }
private:
id data_;
};
#endif /* Wrapper_h */
and the code in question:
-(void)test {
id timer = [NSTimer alloc];
Wrapper* w = new Wrapper(timer); // <-- BAD_ACCESS
}
My end goal is to extend the lifetime of the local id variable with the lifetime of the wrapper (later the wrapper pointer will be stored inside another global variable). Of course when the wrapper is deleted I would like the timer reference count to be decreased to 0.
Here's the stacktrace which looks like a recursive call to retain (stackoverflow):
Trying to bridge retain the timer also crashes:
-(void)test {
id timer = [NSTimer alloc];
CFTypeRef retained = (__bridge_retained CFTypeRef)timer; // <-- BAD_ACCESS
}
Trying to create an std::unique_ptr also will crash:
-(void)test {
id timer = [NSTimer alloc];
std::unique_ptr<id> ptr = std::make_unique<id>(timer); // <-- BAD_ACCESS
}
The code works if I initialize the NSTimer instance:
-(void)test {
id timer = [[NSTimer alloc] init];
Wrapper* w = new Wrapper(timer); // <-- OK
}
I also noticed that other Objective-C types work (such as NSObject, NSString, NSDictionary, NSArray, ...):
-(void)test {
id timer = [NSObject alloc];
Wrapper* w = new Wrapper(timer); // <-- OK
}
So what is special about NSTimer and what would be the proper way to store such instance inside my C++ wrapper? Are there any other examples such as NSTimer that would exhibit similar behaviour?
And a very important detail: this code only crashes iOS 10 (iOS > 10 works fine).
One of golden rule in software development is to follow contracts. For this particular case API states never initialize an object without reassigning any pointer to that object:
Note: It’s possible for init to return a different object than was created by alloc, so it’s best practice to nest the calls as shown.
Never initialize an object without reassigning any pointer to that object. As an example, don’t do this:
NSObject *someObject = [NSObject alloc];
[someObject init];
If the call to init returns some other object, you’ll be left with a pointer to the object that was originally allocated but never initialized.
I should admit though that it doesn't prohibit storing instance returned by the alloc method elsewhere, but Objective-C peculiarities make any use of such instances (apart from initialization) extremely error prone.
First, treat whatever you get from alloc and init... family of methods two different instances to be safe. That comes down to the fact that you have a possibility to return completely different object (even of different class) from an Objective-C constructor. It's one of the reasons why you see expression like self = [super init] (and not just [super init]) in subclassing documentation.
Second, Foundation framework uses Class Cluster design pattern heavily. It's the worst scenario of the previous point and the vast majority of the framework classes are abstract interfaces which hide the actual concrete classes returned by constructors (and even by the alloc method itself).
Thus storing instances returned by alloc essentially means storing abstract factories and it doesn't meet requirements you set for your wrapper (extending lifetime of local variables). Instead you want to keep instances of concrete classes, so wrap instances returned from constructors.
You already found that [[NSTimer alloc] init] doesn't make the code crash but it doesn't look quite correct to me either because the class API doesn't offer argument-less constructor, (it's impossible to get rid of default init from base NSObject in Objective-C, so you need to refer to API documentation to ensure what set of instance initialization is actually available).
What is special about NSTimer?
As i mentioned above Foundation framework classes are all special. And every class is special in its particular way. It's hard to say what exactly is different for NSTimer, however when passing Objective-C instance to a C++ function it follows the same rules, and ARC adds retain/release boilerplate for us, so we can inspect these variables from this standpoint.
I also noticed that other Objective-C types work (such as NSObject,
NSString, NSDictionary, NSArray, ...)
Here is a function which has variables of the given classes:
- (void) listVariables {
NSObject *allocObject = [NSObject alloc];
NSObject *initObject = [allocObject init];
NSString *allocString = [NSString alloc];
NSString *initString = [allocString init];
NSArray *allocArray = [NSArray alloc];
NSArray *initArray = [allocArray init];
NSDictionary *allocDictionary = [NSDictionary alloc];
NSDictionary *initDictionary = [allocDictionary init];
NSTimer *allocTimer = [NSTimer alloc];
NSTimer *initTimer = [allocTimer init];
NSTimer *properlyInitTimer = [allocTimer initWithFireDate:[NSDate date] interval:10 repeats:YES block:nil];
return;
}
Let's see what lldb debugger can reveal when stopped at the line with return expression:
(lldb) frame variable
...
(NSObject *) allocObject = 0x00006000025a0070
(NSObject *) initObject = 0x00006000025a0070
(NSPlaceholderString *) allocString = 0x00007fff801d75e8 class name = NSPlaceholderString
(__NSCFConstantString *) initString = 0x00007fff801dcfa0 ""
(__NSPlaceholderArray *) allocArray = 0x00007fff80198af0
(__NSArray0 *) initArray = 0x00007fff8002e970 0 elements
(__NSPlaceholderDictionary *) allocDictionary = 0x00007fff801a6a40
(__NSDictionary0 *) initDictionary = 0x00007fff8019fb60 0 key/value pairs
(NSCFTimer *) allocTimer = 0x00006000025a02f0
(NSTimer *) initTimer = nil
(__NSCFTimer *) properlyInitTimer = 0x00006000012a8180
Here you can see what these variables are turned into under the hood. This are private classes of course and they may change in future release but i would not expect drastic changes. The most simple is NSObject, an instance returned from alloc matches the instance returned from a constructor (this is part of API description, btw, so i would expect the same transparency for this project in all releases). If i print retain count for this instance, it gives pretty much expected value:
(lldb) po [allocObject retainCount]
2
(lldb) po [initObject retainCount]
2
If i print retainCount value for any of NSString, NSArray or NSDictionary variables in this frame, they all are equal to 2^64-1.
(lldb) po [initString retainCount]
18446744073709551615
Such a huge value essentially means that this instance is a singleton object. Such objects have release and retain methods overridden in a way that it doesn't affect their referenceCount and they exist within entire application life. That is a special kind of optimization for these objects.
From frame command output we can see that initTimer is nil and it doesn't make much sense to check its retain count or how retain works with it - this is a null object. If i print retainCount for the properlyInitTimer, it's quite straightforward:
(lldb) po [properlyInitTimer retainCount]
1
If i do the same for the allocTimer variable the result is kind of unexpected. The debugger gets frozen and entire process starts consuming 100% of CPU. My best bet it could be the reason behind the BAD_ACCESS error. (some kind of Reference Counting suppression introduced as part of the NSTimer abstract factory instance so it could not be removed) and Apple just made it less harmful in latest releases, after iOS 10, but of course i cannot know what exactly is there. (you can freely use retain and release methods on this instance but it apparently cannot be destroyed)
Related
What I was doing before was that I was calling a function of my interface and it determinate in a switch condition thanks to a parameter what to do with the data. What kind of specialization they have.
But now, what I am trying to create a local object, treat it, and then add it to my containers of the interface.
In order to do that I have to copy all the value of my local object (which have been treated) in my container of the interface.
So I created a copy_cell function in the interface, a virtual one, and one in the subclass. But whenever I try to do it the interface function is called and not the subfunction.
GridCell_voxel * local_cell;
local_cell = new GridCell_voxel(m_grid_map( cell2matindex_x(cell_index_x), cell2matindex_y(cell_index_y))->getVoxelResolution(), m_grid_map( cell2matindex_x(cell_index_x), cell2matindex_y(cell_index_y))->getVoxel().size());
local_cell->process_points(relevant_points, m_mapping_type);
//This is the line I need to change
local_cell->copy_cell (m_grid_map( cell2matindex_x( cell_index_x), cell2matindex_y( cell_index_y))) ;
Do you have any idea on the way to go? What am I missing here?
Sorry for the lack of information, i will try to expose how i managed and what i was actually looking for.
So i have a container of IntefaceCell, called m_grid_map, full of cell that has been specialized. In my case m_grid_map is full of GridCell_voxel which is a sub class from InterfaceCell.
What i want to do is, create a new local GridCell_voxel, copy the information in it. Then process the informations, then copy the local cell in the container.
The important part is the dynamic_cast in the copy cell function, which allow you to take an InterfaceCell as argument and then treat it as GridCell_voxel.
//Main.cpp
GridCell_voxel * local_cell;
local_cell = new GridCell_voxel();
local_cell->copy_cell (m_grid_map( cell2matindex_x( cell_index_x), cell2matindex_y( cell_index_y)));
local_cell->process_points(relevant_points, m_mapping_type);
m_grid_map( cell2matindex_x( cell_index_x), cell2matindex_y( cell_index_y))->copy_cell (local_cell);
delete local_cell;
//GridCell_voxel.cpp
void GridCell_voxel::copy_cell(GridCellInterface* cell) {
GridCell_voxel* voxel_cell = dynamic_cast<GridCell_voxel*>(cell);
this->m_voxel_start_height = voxel_cell->m_voxel_start_height;
this->init = true;
this->m_ground_voxel_position = voxel_cell->m_ground_voxel_position;
}
I hope it will help someone.
If a page or component class has one instance field which is a non-synchronized object, f.ex. an ArrayList, and the application has code that structurally modifies this field, should the access to this field be synchronized ?
F.ex.:
public class MyPageOrComponent
{
#Persist
private List<String> myList;
void setupRender()
{
if (this.myList == null)
{
this.myList = new ArrayList<>();
}
}
void afterRender(MarkupWriter writer)
{
// Should this be synchronized ?
if (someCondition)
{
this.myList.add(something);
}
else
{
this.myList.remove(something);
}
}
}
I'm asking because I seem to understand that Tapestry creates only one instance of a page or component class and it uses this instance for all the connected clients (but please correct me if this is not true).
In short the answer is no, you don't have to because Tapestry does this for you. Tapestry will transform your pages and classes for you at runtime in such a way that wherever you interact with your fields, they will not actually be working on the instance variable but on a managed variable that is thread safe. The full inner workings are beyond me, but a brief reference to the transformation can be found here.
One warning, don't instantiate your page/component variables at decleration. I have seen some strange behaviour around this. So don't do this:
private List<String> myList = new ArrayList<String>;
Tapestry uses some runtime byte code magic to transform your pages and components. Pages and components are singletons but the properties are transformed so that they are backed by a PerThreadValue. This means that each request gets it's own copy of the value so no synchronization is required.
As suggested by #joostschouten you should never initialize a mutable property in the field declaration. The strange behaviour he discusses is caused beacause this will be shared by all requests (since the initializer is only fired once for the page/component singleton). Mutable fields should instead be initialized in a render method (eg #SetupRender)
I am porting some code from C++ to Swift that used Grand Central Dispatch, and I am finding a curious error with dispatch_queue_create seemingly not working at all.
For instance, in my C++ base class header, I would declare
dispatch_queue_t m_WorkQ;
and in the initializer, put
m_ResultQ = dispatch_queue_create("com.myapp.mHitsUpdateQueue", 0);
... and everything was glorious.
I've tried this in Swift, in my class, declaring this at class level:
var resultQueue: dispatch_queue_t
... and in the initalizer, I have (among others) the line
resultQueue = dispatch_queue_create("com.myapp.mHitsUpdateQueue", 0)
... and it compiles and starts up fine, but gives me an immediate runtime error of EXC_BAD_ACCESS (code=1, address = 0x37) on the above line
To determine if it's anything else I've done, I created a command line tool application consisting only of the following code:
import Foundation
var thisQueue = dispatch_queue_create("com.myApp.mHitsUpdateQueue", 0)
println(thisQueue.description)
... and sure enough, I get the above error right on the "thisQueue" assignment line. So I'm pretty sure there's something really obvious about Swift and GCD queue creation that I'm missing.
Can anyone please help me out here?
The second argument of dispatch_queue_create() has the type
dispatch_queue_attr_t, which is declared as
typealias dispatch_queue_attr_t = NSObject
You have to pass DISPATCH_QUEUE_SERIAL or nil for a serial queue
(or DISPATCH_QUEUE_CONCURRENT for a concurrent queue):
var thisQueue = dispatch_queue_create("com.myApp.mHitsUpdateQueue", DISPATCH_QUEUE_SERIAL)
In C(++), 0 can be passed instead of a NULL pointer.
The Swift compiler, however, wraps the integer 0 into an NSNumber object
so that it can be passed to the function expecting an NSObject
parameter. That causes the runtime exception because NSNumber is
not a valid attribute. So passing 0 or nil is
significantly different in Swift.
Is it possible to get an existing object reference using CEF API?
For example I run a script using ExecuteJavaScript()
function foo()
{
var self = this;
self.value="some value";
}
var fooObj = new foo;
This script creates a new variable fooObj. It is possible to get a reference to this variable later in the C++ code and to modify its value?
You should be able to get it by doing something like the following (untested):
auto context = AppGetBrowser()->GetMainFrame()->GetV8Context();
CefRefPtr<CefV8Value> p = context->GetGlobal()->GetValue(CefString("fooObj"));
You may need to Enter/Exit the context depending on where you're calling it from in C++. Furthermore you may need to actually reference your object explicitly as 'window.fooObj' in which case you'll have to get the value for 'window' and then get 'fooObj' off that.
(edit - accidentally posted too early)
(edit 2 - more)
I cannot access values in Flex Object (ArrayCollection) after I receive it from Zend AMF. The original type sent is PHP associative array which is simply returned like
return $this->sections['initial_setup'];
PHP Variable view:
The required result sent looks like this in Charles AMF RPC tab:
But when I receive the data in Flex as Object (or String[] - it doesn't matter), I cannot access the property values in such code
var result:Object = event.result;
if (result['database'] == 'yes' && result['admin'] == 'yes')
// continue branch ...
and I get exception on the if-line:
Error: Unknown Property: 'database'.
at mx.collections::ListCollectionView ...
Finally, I can see in Eclipse variables view that ResultEvent instance carries a result of type ArrayCollection with 0 length and the values received are visible with D icon (I couldn't find what D adornment means):
But why I still can't access them at all and what should I do to use them?
I have tried to change types of Array or ArrayCollection instead of Object. Also there is a thread discussing similar problem, but after trying that out, it doesn't help too.
Any help will be much appreciated :o)
EDIT 1:
Here is the code of FB generated super class constructor for the ConfigurationService:
// Constructor
public function _Super_ConfigurationService()
{
// initialize service control
_serviceControl = new mx.rpc.remoting.RemoteObject();
// initialize RemoteClass alias for all entities returned by functions of this service
var operations:Object = new Object();
var operation:mx.rpc.remoting.Operation;
operation = new mx.rpc.remoting.Operation(null, "readSettings");
operation.resultType = Object;
operations["readSettings"] = operation;
operation = new mx.rpc.remoting.Operation(null, "writeSettings");
operations["writeSettings"] = operation;
operation = new mx.rpc.remoting.Operation(null, "readDBSettings");
operation.resultType = valueObjects.ConnectionParams;
operations["readDBSettings"] = operation;
operation = new mx.rpc.remoting.Operation(null, "writeDBSettings");
operations["writeDBSettings"] = operation;
operation = new mx.rpc.remoting.Operation(null, "readInitSetupCompletion");
operation.resultType = Object;
operations["readInitSetupCompletion"] = operation;
operation = new mx.rpc.remoting.Operation(null, "writeInitSetupCompletion");
operations["writeInitSetupCompletion"] = operation;
_serviceControl.operations = operations;
_serviceControl.convertResultHandler = com.adobe.serializers.utility.TypeUtility.convertResultHandler;
_serviceControl.source = "ConfigurationService";
_serviceControl.endpoint = "gateway.php";
preInitializeService();
model_internal::initialize();
}
So what's happened here is that the Array that's serving as the source for your ArrayCollection is acting as a generic Object with those same two properties. Probably the generated code is assuming you'll always get back more than one object and is having problems when your data doesn't fulfill the assumptions Adobe's engineers made about it. One of the reasons I don't like generated code :-).
Check out these resources on how to "roll your own."
Thoughts on Remoting
AMFPHP to Flex Object Relational Mapping
Implementing PHP Services
I think this last (3) is closest to what you probably have in PHP. If you do decide to go with a VO, you can probably just add an $explicitType to your row return and not need to change too much else on the PHP side. You'll probably need to regenerate your services if you go that route, because I suspect the generated code will be different. The good news is the Adobe engineers probably did think of the case where you have an explicit type, but only one record.
Another fix is to just check your AC for having a source of zero length that is not null and looking for your properties on the edges of that.