I have a Swift project that's using AVCaptureSession to take photos within the app. I'm having difficulty getting the right syntax to properly clean up my objects. In Obj-C the suggested code would be as follows;
// Releases the object - used for late session cleanup
static void capture_cleanup(void* p)
{
NewPostPreviewViewController* csc = (NewPostPreviewViewController*)p;
[csc release]; // releases capture session if dealloc is called
}
// Stops the capture - this stops the capture, and upon stopping completion releases self.
- (void)stopCapture {
// Retain self, it will be released in capture_cleanup. This is to ensure cleanup is done properly,
// without the object being released in the middle of it.
[self retain];
// Stop the session
[session stopRunning];
// Add cleanup code when dispatch queue end
dispatch_queue_t queue = dispatch_queue_create("VideoDataOutputQueue", NULL);
dispatch_set_context(queue, self);
dispatch_set_finalizer_f(queue, capture_cleanup);
[dataOutput setSampleBufferDelegate: self queue: queue];
dispatch_release(queue);
}
The finalizer would call capture_cleanup but I have no idea how to set the context or the pointer to the capture_cleanup function (or even what the function definition would look like)
So far I've tried the following but I'm not convinced I'm even on the right track;
let p: UnsafeMutablePointer<NewPostPreviewViewController> = UnsafeMutablePointer.alloc(sizeof(NewPostPreviewViewController))
p.initialize(self)
var videoDataOutputQueue = dispatch_queue_create("VideoDataOutputQueue", nil)
dispatch_set_context(videoDataOutputQueue, p)
dispatch_set_finalizer_f(videoDataOutputQueue, ????);
self.videoDataOutput!.setSampleBufferDelegate(self, queue: videoDataOutputQueue)
dispatch_release(videoDataOutputQueue)
Any help converting this would be most appreciated!
Solved using bridging to Objective-C code. By including a CameraController.m Objective-C class in my Swift project (with associated header) I bridge for access to the camera feed.
The Objective-C class does all the work I need, and stores the last image taken. It also produces a notification once the image is taken, allowing my Swift class to observe the notification and go get the last image taken.
Related
I'm developing a ble-based native local multiplayer plugin for Unity (for both Android and iOS). I use a single service, with a single characteristic with rw permissions. I've managed to make Android<->Android and iOS<->iOS work all right, but I'm having a rough time trying to make Android<->iOS work. Specifically, it's the 'iOS as Peripheral, Android as Central' combination the one that keeps me up at night. After many hours of fiddling, testing, googling and trying, I have very much pinned down the problem to this:
From the Android side, if I don't subscribe to the characteristic, a call to BluetoothGatt#writeCharacteristic(characteristic), like this:
String str = "the data";
xferCharacteristic.setValue(str.getBytes("UTF-8"));
mGatt.writeCharacteristic(xferCharacteristic);
will return 'true' and succeed, and the peripheralManager:didReceiveWriteRequests: callback will be called on the iOS side where I can manipulate the precious received data as I see fit. So far so good. But, if I try to update a characteristic from the iOS end, the Android central won't get notified (the callback BluetoothGattCallback#onCharacteristicChanged should be called, but it isn't), since it did not subscribe to the characteristic.
If I make the Android central subscribe to the characteristic offered by the iOS peripheral, by means of this section of code:
First, connect to the iOS peripheral with
public void onScanResult(int callbackType, ScanResult result) {
BluetoothDevice btDevice = result.getDevice();
mGatt = device.connectGatt(appContext, false, mGattCallback);
...
with mGattCallback an instance of BLEGattCallback which will handle the onServicesDiscovered callback:
public class BLEGattCallback extends BluetoothGattCallback {
private static final UUID CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
List<BluetoothGattService> services = gatt.getServices();
for(BluetoothGattService s : services) { // foreach service...
if(UUID.fromString(MyServiceUUID).equals(s.getUuid())) { // just the one I want...
List<BluetoothGattCharacteristic> characteristics = s.getCharacteristics();
for(BluetoothGattCharacteristic c : characteristics) { // foreach characteristic...
if(c.getUuid().toString().equals(BLEManager.FGUUIDXferQueueString)) { // just the char. I want...
c.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
for (BluetoothGattDescriptor descriptor : c.getDescriptors()) {
if(descriptor.getUuid().equals(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID)) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descriptor);
}
}
gatt.setCharacteristicNotification(c, true);
}
}
}
}
}
This makes the Android central correctly subscribe for the characteristic (the callback method peripheralManager:central:didSubscribeToCharacteristic: is called on the iOS peripheral), BUT, if i do this, the call to mGatt.writeCharacteristic(xferCharacteristic) will return 'false' and no data will be written to the peripheral, so it's a kind of can-only-write or can-only-notify-update situation.
I have unsuccessfully tried to find out the meaning of writeCharacteristic returning 'false', to no avail (seriously, an error code would help a lot).
I've tried a lot of different combinations, values, etc... but, bottom line: as soon as I call gatt.writeDescriptor subsequent calls to writeCharacteristic will fail, and if I don't call gatt.writeDescriptor the android central won't subscribe.
I'm pretty much stuck here. Any help appreciated. Thanks a lot.
Classic issue. You must wait for the operation to complete before you can issue another one. See Android BLE BluetoothGatt.writeDescriptor() return sometimes false.
Thanks to the received hint, this issue has been solved. These are the changes I made to the code:
The Android client must wait for the writeDescriptor(...) request to finish before issuing a writeCharacteristic(...) command. For that, I had to #Override the method onDescriptorWrite on my BLEGattCallback class, which will be called when the writeDescriptor operation completes. I moved my first writeCharacteristic(...) call here, and now the information is sent to the iOS endpoint (the rest must be flow-controlled). So I'm very happy.
I'm using PNaCl and I'm in a situation where first I receive a message that is handled in the 'HandleMessage' function as the normal way, but then in the current HandleMessage execution, I need to wait for a user input that would come from an other message in order to complete the execution.
I'm wondering if this is possible to do that (handling a message while already waiting in the 'HandleMessage' function) ? And if so, can someone give me a trick ?
Thanks !
HandleMessage is currently called on one thread, the main thread. So you cannot receive a message while you are handling another message.
We typically suggest you spawn a new thread to do your work, and leave the main thread to handle messages, and queue them for the new thread to handle. Take a look at the nacl_io_demo example in the SDK for an example of this technique (found in examples/demo/nacl_io).
Another solution is to use a state machine; i.e. keep track of your current state in a variable instead of on the stack.
For example:
enum State {
STATE_INIT,
STATE_WAITING_FOR_INPUT,
STATE_DO_OTHER_STUFF,
};
State state_;
virtual void HandleMessage(const pp::Var& var_message) {
switch (state_) {
case STATE_INIT:
if (var_message.AsString() == "first_message") {
state_ = STATE_WAITING_FOR_INPUT;
// Do some work before you need the user input ...
}
break;
case STATE_WAITING_FOR_INPUT:
if (var_message.AsString() == "user_input") {
// Do more work, now that we've received input from the user...
state_ = STATE_DO_OTHER_STUFF;
}
break;
}
}
Here is basically what is happening....
Class A (Main thread) sends an MVVM message
This message is received, and in the course of processing, Class B is constructed and kicks off a background task.
This background sends an seperate MVVM message.
Class C has registered for this message and does an invoke on the dispatcher to attempt to update the UI.
At this point the main thread is still executing the original Send command and the threads are deadlocked (I can pause the debugger and see they are both waiting).
Other Notes
If I add a sleep in the background thread for one second (allowing the main thread's Send method to complete) it works fine.
This only happens if there is a nested MVVM message sent on another thread which invokes on the dispatcher.
Commenting out the dispatcher call...fine.
Not using an MVVM message to invoke the dispatcher...fine.
Can anyone explain what is going on?
I'll take a stab at this...
You can take a look at the MVVM-Light source code on its CodePlex site. I'm going to paste in the relevant method here (slightly annotated for the sake of this post):
private void SendToTargetOrType<TMessage>(TMessage message, Type messageTargetType, object token)
{
var messageType = typeof(TMessage);
if (_recipientsOfSubclassesAction != null)
{
// Clone to protect from people registering in a "receive message" method
// Correction Messaging BL0008.002
var listClone =
_recipientsOfSubclassesAction.Keys.Take(_recipientsOfSubclassesAction.Count()).ToList();
foreach (var type in listClone)
{
List<WeakActionAndToken> list = null;
if (messageType == type
|| messageType.IsSubclassOf(type)
|| type.IsAssignableFrom(messageType))
{
lock (_recipientsOfSubclassesAction)
{
list = _recipientsOfSubclassesAction[type].Take(_recipientsOfSubclassesAction[type].Count()).ToList();
}
}
// Class A probably sends a message here from the UI thread
SendToList(message, list, messageTargetType, token);
}
}
if (_recipientsStrictAction != null)
{
// Class B grabs this lock on the background thread.
// Class A continues processing on the UI thread and arrives here.
// An attempt is made to grab the lock on the UI thread but it is
// blocked by the background thread & Class B which in turn is waiting
// on the UI thread. And here you have yourself a deadlock
lock (_recipientsStrictAction)
{
if (_recipientsStrictAction.ContainsKey(messageType))
{
var list = _recipientsStrictAction[messageType]
.Take(_recipientsStrictAction[messageType].Count())
.ToList();
// Class B sends its message here.
// Class C receives the message and does an Invoke on the UI thread
SendToList(message, list, messageTargetType, token);
}
}
}
RequestCleanup();
}
Class A probably sends a message on the UI thread picked up by 'subclass recipients'.
Class B is a recipient that picks up this message and kicks off your background task.
Your background task then sends a message that has a 'strict action recipient'.
Class B grabs the '_recipientsStrictAction' lock on the background thread.
Class B sends the message to class C, which does an invoke on the UI thread.
This invoke blocks because the UI thread is still executing the first message.
UI thread execution continues on and then tries to grab the '_recipientsStrictAction' lock on the UI thread. Unfortunately, your background thread (which is waiting on the UI thread) already has the lock. You are now deadlocked :(
Might want to consider doing an InvokeAsync in Class C rather than an Invoke. I think you could probably avoid the issue that way.
Makes me wonder why MVVM light is sending the message 'inside' the lock. Seems like a not-so-cool sort of thing to do. After typing all this up, I went looking around the CodePlex site, looks like this is issue has been documented:
http://mvvmlight.codeplex.com/workitem/7581
I have an NSMutableArray called message that I've alloc'd in init and release in dealloc. I can usually use a string in a CCCallFuncND action without a problem, even if it's an index of an array, such as:
displayMessagePiece = [CCCallFuncND actionWithTarget:self selector:#selector(displayMessageBoxString : data:) data:[[NSString stringWithFormat:[labelPieces objectAtIndex:i]] retain]];
However, if I use my mutable string, I get a crash with a green arrow pointing to my line of code that I have it in, and it says "EXC_BAD_ACCESS" with some hexadecimal.
Here's my action and sequence where I'm trying to use NSMutableString:
id displayMessage = [CCCallFuncND actionWithTarget:self selector:#selector(displayMessageBoxString : data:) data:[[NSString stringWithFormat:[message copy]] retain]];
[self runAction:[CCSequence actions:displayMessage,nil]];
Notice I use [message copy], although I've tried also just message.
I smell bad practice:
NSString* s = [[NSString stringWithFormat:[labelPieces objectAtIndex:i]] retain];
[CCCallFuncND actionWithTarget:self
selector:#selector(displayMessageBoxString:data:)
data:s];
First of all you are retaining a string that you may or may not be releasing. There is no guarantee that the displayMessageBoxString selector ever gets called. For example, the node running the call func action may be removed from the scene before the selector is called, or you may be changing the entire scene before the selector is called. In both cases you will be leaking the string.
There's also no reason to use CCCallFuncND when there's CCCallFuncO. CCCallFuncND is particularly harmful when your project is using ARC. In that case you'd have to bridge cast the object to void*, at which point ARC might simply release the memory, rightfully assuming that non-ARC code now manages the object's memory. The same may actually be true for autorelease, but I'm not 100% certain about that.
So first order of business is to use CCCallFuncO and re-test if your problem is gone. Also rely on autorelease, do not retain the string since you will not be able to release it in all cases.
NSString* s = [NSString stringWithFormat:[labelPieces objectAtIndex:i]];
[CCCallFuncO actionWithTarget:self
selector:#selector(displayMessageBoxString:)
object:s];
Now if your minimum target is iOS 4.0, you should really be using blocks instead. This is particularly true if you need both sender and object at the same time. The block has access to the local scope, so you can use the simplest CCCallBlock action in this case:
NSString* s = [NSString stringWithFormat:[labelPieces objectAtIndex:i]];
[CCCallBlock actionWithBlock:^void(){
CCLOG(#"sender is: %#, string is: %#", self, s);
}];
Et voila, all problems solved and guaranteed not to cause any memory leaks.
Note that you can also write the block without void() like this:
[CCCallBlock actionWithBlock:^{
CCLOG(#"sender is: %#, string is: %#", self, s);
}];
Personally I find it helpful to remind myself and others about the return type and parameters, even if there are none.
I've been trying to track down memory leaks in our application, and keep finding myself back looking at Spark components as the culprit.
I think I've found the cause, but my understanding of Garbage Collection / mark & sweep is not too hot, so I'd like to verify my findings.
Many classes in Spark use RichEditableText for displaying their text properties (ComboBox,TextInput).
RichEditableText has a local textContainerManager property, and frequently calls compose() on this.
Here's the relevant abridged extract from TextContainerManager
// Line 282 - 292:
static private var stringFactoryDictionary:Dictionary = new Dictionary(true);
static private function inputManagerStringFactory(config:IConfiguration):StringTextLineFactory
{
var factory:StringTextLineFactory = stringFactoryDictionary[config];
if (factory == null)
{
factory = new StringTextLineFactory(config);
stringFactoryDictionary[config] = factory;
}
return factory;
}
// Line 1204:
public function compose() {
// Line 1238:
var inputManagerFactory:TextLineFactoryBase = (_sourceState == SOURCE_STRING) ? inputManagerStringFactory(_config) : _inputManagerTextFlowFactory;
// Line 1242:
inputManagerFactory.swfContext = Configuration.playerEnablesArgoFeatures ? this : _swfContext;
}
Line 1242 is the crucial line here, as it gives the static dictionary a reference to our component.
(Note - I've checked this with the debugger to confirm which branch of the ternary gets executed.) This would prevent the instance from ever being garbage collected.
Eg: Static dictionary has a value with a reference to the instance -- instance cannot be GC'd.
In turn, this would prevent any other instances which have a reference to the instance of TextContainerManager from being GC'd also.
While this theory certainly matches what I'm seeing in our app, I can't beleive that there really is a memory leak in such a low-level spark component.
Could someone please shed some light on this?
BTW - I've opened a defect on bugs.adobe.com to track this issue, should it prove to be a genuine bug:
https://bugs.adobe.com/jira/browse/SDK-29531
I've heard there are several memory problems related to TLF.
That should be corrected in the Flex 4.5 SDK.
In the meantime, you could still open a ticket on http://bugs.adobe.com/jira/