Device not seen as attached magnetic swiper iOS - ios

SoI have a device (unimag II) attached using their api I redid some of their methods to be compatible with the way I want my app to flow and run. However I now am running into issues such as [UM Info] SDK: initialized UM Warning] StartSwipe: UMRET_NO_READER as well as the swipe starting not being hit when other notifications are. Clearly I am missing something but I have blown so much time on this that I have no clue what I possibly could miss since I made sure that I was as close to their sample app as possible. Obviously there is more code but this is where it should be getting set as opened I would think
-(void)enableSwipe:(CDVInvokedUrlCommand*)command{
[self umsdk_activate];
UmRet ret = [uniReader requestSwipe];
[self displayUmRet: #"Starting swipe task" returnValue: ret];
}
-(void) umsdk_registerObservers:(BOOL) reg {
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
//list of notifications and their corresponding selector
const struct {NSString __unsafe_unretained *n; SEL s;} noteAndSel[] = {
//
{uniMagAttachmentNotification , #selector(umDevice_attachment:)},
{uniMagDetachmentNotification , #selector(umDevice_detachment:)},
//
{uniMagInsufficientPowerNotification, #selector(umConnection_lowVolume:)},
{uniMagMonoAudioErrorNotification , #selector(umConnection_monoAudioError:)},
{uniMagPoweringNotification , #selector(umConnection_starting:)},
{uniMagTimeoutNotification , #selector(umConnection_timeout:)},
{uniMagDidConnectNotification , #selector(umConnection_connected:)},
{uniMagDidDisconnectNotification , #selector(umConnection_disconnected:)},
//
{uniMagSwipeNotification , #selector(umSwipe_starting:)},
{uniMagTimeoutSwipeNotification , #selector(umSwipe_timeout:)},
{uniMagDataProcessingNotification , #selector(umDataProcessing:)},
{uniMagInvalidSwipeNotification , #selector(umSwipe_invalid:)},
{uniMagDidReceiveDataNotification , #selector(umSwipe_receivedSwipe:)},
//
{uniMagCmdSendingNotification , #selector(umCommand_starting:)},
{uniMagCommandTimeoutNotification , #selector(umCommand_timeout:)},
{uniMagDidReceiveCmdNotification , #selector(umCommand_receivedResponse:)},
//
{uniMagSystemMessageNotification , #selector(umSystemMessage:)},
{nil, nil},
};
//register or unregister
for (int i=0; noteAndSel[i].s != nil ;i++) {
if (reg)
[nc addObserver:self selector:noteAndSel[i].s name:noteAndSel[i].n object:nil];
else
[nc removeObserver:self name:noteAndSel[i].n object:nil];
}
}
-(void) umsdk_activate {
//register observers for all uniMag notifications
[self umsdk_registerObservers:TRUE];
NSLog(#"activating");
//enable info level NSLogs inside SDK
// Here we turn on before initializing SDK object so the act of initializing is logged
[uniMag enableLogging:TRUE];
//initialize the SDK by creating a uniMag class object
uniReader = [[uniMag alloc] init];
/*
//set SDK to perform the connect task automatically when headset is attached
[uniReader setAutoConnect:TRUE];
*/
//set swipe timeout to infinite. By default, swipe task will timeout after 20 seconds
[uniReader setSwipeTimeoutDuration:0];
//make SDK maximize the volume automatically during connection
[uniReader setAutoAdjustVolume:TRUE];
//By default, the diagnostic wave file logged by the SDK is stored under the temp directory
// Here it is set to be under the Documents folder in the app sandbox so the log can be accessed
// through iTunes file sharing. See UIFileSharingEnabled in iOS doc.
[uniReader setWavePath: [NSHomeDirectory() stringByAppendingPathComponent: #"/Documents/audio.caf"]];
}

Related

NSNotificationCenter posting notifications doesn't work

I have a func which uses the nw_path_monitor_t to register for network events.
// Entry point.
// Will be called from AppDelegate when app starts up
void TestNWPathMonitor () {
PrintToFile("TestingNWPathMonitor\n");
NotificationReceiver *notification_receiver = [[NotificationReceiver alloc] init];
// Set up the notification receiver to listen for wifi notification
[notification_receiver RegisterNotification];
monitor = nw_path_monitor_create ();
nw_path_monitor_set_update_handler (monitor, WifiNetworkChangeCB);
nw_path_monitor_start(monitor);
}
I've provided the callback, which will be invoked when there is a change in network events. In the callback (as shown below), I'm looking out for wifi events and posting a notification to the default notification center.
nw_path_monitor_update_handler_t WifiNetworkChangeCB = ^ (nw_path_t path) {
PrintToFile("Wifi Network change!!\n");
nw_path_status_t status = nw_path_get_status (path);
if (nw_path_uses_interface_type (path, nw_interface_type_wifi)) {
if (status == nw_path_status_satisfied) {
PrintToFile("nw_path_status_satisfied\n");
[[NSNotificationCenter defaultCenter] postNotificationName:#"WifiNetworkChange" object:nil];
} else {
PrintToFile("!(nw_path_status_satisfied)\n");
}
}
};
This is the NotificationReceiver class:
// NotificationReceiver.h
#include <Foundation/Foundation.h>
#interface NotificationReceiver : NSObject
- (void) HandleNotification : (NSNotification *) pNotification;
- (void) RegisterNotification ;
#end
// NotificaitonReceiver.m
#implementation NotificationReceiver
- (void) HandleNotification : (NSNotification *) pNotification {
PrintToFile([[NSString stringWithFormat:#"Received notification: %#\n", pNotification.name] UTF8String]);
}
- (void) RegisterNotification {
PrintToFile("RegisterNotification!\n");
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(HandleNotification:) name:#"WifiNetworkChange" object:nil];
}
#end
RegisterNotification, called at the beginning (as shown in the first code snippet) will add the instance as an observer and HandleNotification is the receiver of the wifi notification posted from the WifiNetworkChangeCB block.
The problem is, when I receive the wifi event, the WifiNetworkChangeCB is invoked and the postNotificationName function is executed (Have verified with the debugger), but HandleNotification doesn't receive the notification.
I'm getting the following output:
TestingNWPathMonitor
RegisterNotification!
Wifi Network change!!
Whereas, the expected output is:
TestingNWPathMonitor
RegisterNotification!
Wifi Network change!!
Received notification: WifiNetworkChange
I have read the documentation of the notification center to understand its usage. Have also referred this answer.
I have also referred the documentation of the funcs I'm using (added them as hyperlinks while explaining the problem), everything seems fine.
But I'm obviously missing something (Since it didn't work). Any help will be greatly appreciated.
Reason: your C function TestNWPathMonitor() allocates NotificationReceiver *notification_receiver but the object created is nowhere stored when you leave the scope. So with ARC memory management the object will be released when the scopes block is left, aka its stack is "empty" again.
your monitor aka typedef NSObject<OS_nw_path_monitor> *nw_path_monitor_t; seems to be a global so it will still exist after leaving the scope giving you possibly the misconception that same would be the case for objc allocations, well yes and no. Same would have happend to monitor if it would have been a local variable.
Debugging: Observering [NSNotificationCenter defaultCenter] allows you to catch Notifications almost anywhere in your code, no matter what thread you wait for them, its a NSString based API for good reason with all its pro's and cons. Because of that easy approach it can be hard to find why it is not working. But basically placing an Observer in main.m or APPDelegate should always tell you if it is properly working on the posting side to be sure you did not miss-spell the NotificationName. To avoid the latter case we often declare
extern NotificationName const kSomeNiceNotification;
// in .h && the following in .m
NotificationName const kSomeNiceNotification = #"kSomeNiceNotification";
and use this global key instead as name.
Hint: you can also create a single time Notification that will be triggered and destroy itself when received with other implications you have to think of when doing so. like so (from the Xcode docs)..
NSNotificationCenter * __weak center = [NSNotificationCenter defaultCenter];
id __block token = [center addObserverForName:#"OneTimeNotification"
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
NSLog(#"Received the notification!");
[center removeObserver:token];
}];
See [NSOperationQueue mainQueue] in above code snippet?
You could pass nil there but then the notifications block would execute on the thread the notification was send. When used in UI code, which most often is the usecase for Notifications this is important as UI tasks needs to be executed on the main thread where passing nil forces you later on to wrap UI stuff in
dispatch_async(dispatch_get_main_queue(), ^{ /* UI code block */ }); // or
dispatch_sync(dispatch_get_main_queue(), ^{ /* UI code block */ });
which you don't need to do when you told the notification observer where to execute the notifications block when received.
Ps: in objc we start methodnames in small letters, you will run in trouble when setter & getters violate the "camelCased" methodname rule because the interface #property NSObject *someName; becomes -(NSObject*)someName; as getter and -(void)setSomeName:(NSObject*)somename; as setter with modern objc. This tells also why we use the lower underscore to mark local class variables that are the counterparts of almost any property.. in this given example the property NSObject *someName would have an internal _someName counterpart. Not going deeper here as in oldschool objc there is more to know about the class declarations #dynamic ... & #synthesize ... that allow more detailed control of the (internal) local class variable name.
Why to bother about that? Your NotificationReceiver *notification_receiver could override a class property with the same name giving you the impression you made everything right but is still not working as the declaration would still leave the stack empty then. So declaring the variable like _notification_receiver = ... in the methods/function block would make very clear you meant the internal counterpart of its #property NotificationReceiver *notification_receiver; and not a extra local variable.

iOS - Objective-C - widget texts and images are doubled - old data are not cleared

In iOS app widget, I can see on only some devices, doubled data (see figure below). I have tried to identify device, iOS version, but it seems to be "random". Plus, I am unable to debug this by myself, because on every of my devices, all is rendered correctly and doing blind debugging is not working (several updates on AppStore but still with the same error).
In widget, I download (in background thread) new data from web and put them (in dispatch_get_main_queue()) into labels, images etc. All is working OK, but sometimes the old data are not "cleared". In my design file for widget, I have cleared all "default" texts, so this is not this problem.
Doubled icon & texts 4.1°C and 7.9°C are overlapping
Main part of my widget code is (shortened by removing other labels, tables and geolocation):
- (void)viewDidLoad
{
[super viewDidLoad];
if ([self.extensionContext respondsToSelector:#selector(widgetLargestAvailableDisplayMode)])
{
//this is iOS >= 10
self.extensionContext.widgetLargestAvailableDisplayMode = NCWidgetDisplayModeExpanded;
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(FinishDownload:) name:#"FinishDownload" object:nil];
self.preferredContentSize = CGSizeMake(320, 160);
[self updateData];
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self updateData];
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self updateData];
}
-(void)updateData
{
[[[DataManager SharedManager] settings] Reload];
[[CoreDataManager SharedManager] reset];
if ([[DataManager SharedManager] DownloadDataWithAfterSelector:#"FinishDownload"] == NO)
{
//no need to download update - refill data now
//if downloading - wait for download
[self FillData];
}
}
}
-(void)FinishDownload:(NSNotification *)notification
{
dispatch_async(dispatch_get_main_queue(), ^{
[self FillData];
});
}
-(void)FillData
{
//a lot of code - example of setting temperature
NSString *str = [NSString stringWithFormat:#"%# °C", act.temp_act];
self.lblTemp.text = str;
[self.lblTemp sizeToFit];
if (self.completionHandler != nil)
{
self.completionHandler(NCUpdateResultNewData);
}
}
- (void)widgetPerformUpdateWithCompletionHandler:(void (^)(NCUpdateResult))completionHandler
{
// Perform any setup necessary in order to update the view.
// If an error is encountered, use NCUpdateResultFailed
// If there's no update required, use NCUpdateResultNoData
// If there's an update, use NCUpdateResultNewData
//completionHandler(NCUpdateResultNewData);
NSLog(#"=== widgetPerformUpdateWithCompletionHandler === ");
self.completionHandler = completionHandler;
[self updateData];
}
- (UIEdgeInsets)widgetMarginInsetsForProposedMarginInsets:(UIEdgeInsets)defaultMarginInsets
{
return UIEdgeInsetsMake(0, 0, 5, 5);
}
- (void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize
{
if (activeDisplayMode == NCWidgetDisplayModeExpanded)
{
self.preferredContentSize = CGSizeMake(320, 160);
}
else if (activeDisplayMode == NCWidgetDisplayModeCompact)
{
self.preferredContentSize = maxSize;
}
}
View Lifecycle
Do not duplicate the work in viewDidLoad and viewWillAppear/viewDidAppear.
A view that was loaded will hit all three methods. Use viewDidLoad for operations that must be performed exactly once for the life of the UIViewController.
Potential problem:
Triggering 3 invocations, possibly conflicting, to [self updateData] back to back, possibly with competing NCUpdateResult completion handlers3.
Balance Observers
It appears that addObserver is never balanced by a removeObserver. A good location for these registration methods is a set of balanced messages, such as the view___Appear and view___Disappear methods, as outlined in this StackOverflow answer.
Potential problem:
Lasting registration to notifications on objects that may go out of scope.
Do not cache OS handlers
Possible misuse of NCUpdateResultNewData completion handler: the NCUpdateResult is passed to widgetPerformUpdateWithCompletionHandler to be used for that specific invocation, not stored for multiple reuse. It should probably be handed down to updateData as a parameter rather than stored in a global, in turn passed to FillData, and eventually cleared after a one-time use.
if (nil != self.completionHandler) {
self.completionHandler(NCUpdateResultNewData);
self.completionHandler = nil; // One time use
}
Every invocation to widgetPerformUpdateWithCompletionHandler has its own cycle, as outlined in this StackOverflow answer.
Layout & Autolayout
Be aware that the iOS is making a snapshot of your widget ; in Interface Builder, make sure that you use proper layering of views. Pay special attention to transparency and drawing flags. Leverage Autolayout to resize/size/snap objects
Check the UILabel's options in Interface Builder, make sure 'opaque' is unchecked. If the label is set as opaque, it might not be properly clearing the entire view when you change the text. You probably want to check on the 'clears graphics context' property as well, which should be checked.
In the code you add a Notification observer. You do not remove the observer.
I suspect that the notification will be fired multiple times which will result jn a race condition or something.
Solution:
- check hoe often the addObserver is executed. (Including screen changes like back-forward etc)
remove the observer when the notification is caught.
clear / remove the observer when leaving the VC
Besides: check / reduce the action in the ViewWillAppear and ViwDidAppear.

Crash while getting the current Autofocus system in ios

There are two types of focus detection right from iphone 6 introduction,
1. Contrast detection
2. Phase detection
from iphone 6.6+ it uses phase detection.
I am trying to get the current focus system
self.format = [[AVCaptureDeviceFormat alloc] init];
[self.currentDevice setActiveFormat:self.format];
AVCaptureAutoFocusSystem currentSystem = [self.format autoFocusSystem];
if (currentSystem == AVCaptureAutoFocusSystemPhaseDetection)
{
[self.currentDevice addObserver:self forKeyPath:#"lensPosition" options:NSKeyValueObservingOptionNew context:nil];
}
else if(currentSystem == AVCaptureAutoFocusSystemContrastDetection)
{
[self.currentDevice addObserver:self forKeyPath:#"adjustingFocus" options:NSKeyValueObservingOptionNew context:nil];
}
else{
NSLog(#"No observers added");
}
but now its crashing in the following line
AVCaptureAutoFocusSystem currentSystem = [self.format autoFocusSystem];
I am unable to find proper description for the crash.
You're creating some "AVCaptureDeviceFormat", but nothing is actually set up by default with it. It's just unusable garbage (and that's why you are getting a crash).
Each capture device has one or two formats it can work with.
You can see them by doing something like:
for (AVCaptureDeviceFormat *format in [self.currentDevice formats]) {
CFStringRef formatName = CMFormatDescriptionGetExtension([format formatDescription], kCMFormatDescriptionExtension_FormatName);
NSLog(#"format name is %#", (NSString *)formatName);
}
What you should be doing is deciding which AVCaptureDevice you want to use (e.g. the front camera, the back camera, whatever), getting the format from that, and then setting [self.currentDevice setActiveFormat:self.format]".
The WWDC 2013 session "What's New in Camera Capture" video has more information on how to do this.

Worklight iOS Geofence Native API stops working in background after few mins

I am developing geofencing application using worklight ios native apis.
I am using worklight 6.1 and testing application on my iPhone4 with ios 7.1.2.
Below is the native ios code i have written to create geofence.
WLGeoAcquisitionPolicy* geoPolicy = [WLGeoAcquisitionPolicy getLiveTrackingProfile];
id<WLDevice> wlDevice = [[WLClient sharedInstance] getWLDevice];
// now, set-up configuration for ongoing acquisition
WLLocationServicesConfiguration* config = [[WLLocationServicesConfiguration alloc] init];
// 1. Acquisition Policy (same one that is used for the one-time acquisition)
WLAcquisitionPolicy* policy = [[WLAcquisitionPolicy alloc] init];
[policy setGeoPolicy: geoPolicy];
[config setPolicy:policy];
WLTriggersConfiguration* triggers = [[WLTriggersConfiguration alloc] init];
WLGeoEnterTrigger *wlTypeAEnterRegionTrigger = [[WLGeoEnterTrigger alloc] init];
[wlTypeAEnterRegionTrigger setArea:[[WLCircle alloc] initWithCenter:[[WLCoordinate alloc] initWithLatitude:19.5687f longitude:72.8748f] radius:500.0f]];
[wlTypeAEnterRegionTrigger setConfidenceLevel:HIGH];
[wlTypeAEnterRegionTrigger setCallback:[WLCallbackFactory createTriggerCallback:^(id<WLDeviceContext> deviceContext) {
#try
{
[[triggers getGeoTriggers] removeObjectForKey:"Offer1"];
[self showLocationNotificationWithOfferID:"Offer1" andDescription:#"offer description"];
}
#catch (NSException *exception)
{
NSLog(#"Error Occured in LBSManager::enterTriggerCallBack : %#",[exception description]);
}
}]];
[[triggers getGeoTriggers] setObject:wlTypeAEnterRegionTrigger forKey:"Offer1"];
[config setTriggers:triggers];
[wlDevice startAcquisition:config];
After creating WLGeoEnterTrigger location service icon appears in status bar and after that i am putting application in background after few minutes location service icon disappears.
When i put application in foreground and i get this wlLocationServicesConfiguration as nil.
WLLocationServicesConfiguration *wlLocationServicesConfiguration = [[[WLClient sharedInstance] getWLDevice] getLocationServicesConfig];
I have also added neccessary BackgroundModes still it does not work.
even if i kill the app i get this wlLocationServicesConfiguration as nil.
WLLocationServicesConfiguration *wlLocationServicesConfiguration = [[[WLClient sharedInstance] getWLDevice] getLocationServicesConfig];
I believe the answer to the following question may explain it: MobileFirst 6.3 - Enabling location trigger in Background in Hybrid Applications for iOS environment
The answer by Carmel is as follows:
First see this for how to set permissions to run location services in
the background:
Background Location Services not working in iOS 7
There is limitations in Ios. After couple of minutes of running in the
background without any location update the app get suspend and all the
location update will be received once the user bring the app back to
life.

iCloud - renaming open documents on another device sometimes fails

The issue: I'm working on an iCloud document on device A, e.g. iPod Touch. Then I change the name of the document on device B, e.g. my Mac (via the Finder). The change goes up to the cloud and after a pause device A gets to hear about it.
And then:
some of the time all is just fine - I pick up the change of name via a changed fileURL property and can update my interface accordingly - the document continues to behave just as it should
some of the time, the document's fileURL is returned as something such as: file://localhost/var/mobile/Library/Mobile%20Documents/.ubd/peer-43A0AEB6-84CE-283E-CA39-FCC4EF3BC8F8-v23/ftr/purg-012fdcfbe3b3bbce6e603fdfd2f000b2cb28649e95 Not surprisingly this file won't save.
Can anyone explain what is going on and how to work around it?
Background
The name change is picked up fine by by NSMetadataQuery. So, for e.g., I can rename documents that are not open and all my iCloud functionality works fine. The issue only seems to occur with open documents.
Other iCloud features are working fine, e.g. I can change content on one device, e.g. my Mac, and detect and then update my interface on another device, e.g. my iPod Touch, that has the relevant iCloud document open.
I first spotted this when I added an override for presentedItemDidMoveToURL: to my UIDocument subclass. The override reliably picks up name changes made in the cloud, e.g. renaming the document on another device. Then sometimes newURL is the final expected URL for the renamed document, i.e. something sensible from which I can extract the new name use `lastPathComponent', update my interface etc. On other occasions newURL is a document in some other directory with a last path component beginning 'purg-', e.g. purg-012fdcfbe3b3bbce6e603fdfd2f000b2cb28649e95.
- (void) presentedItemDidMoveToURL:(NSURL *) newURL;
{
[super presentedItemDidMoveToURL: newURL];
if ([(id)[self delegate] respondsToSelector:#selector(documentNameChanged:)])
{
[[self delegate] documentNameChanged: self];
}
}
The presentedItemDidMoveToURL: method does not seem to be the root cause of the problem. For example, if I don't override that method at all, but periodically check in the viewController that is looking after the open document, then sometimes after a rename fileURL will return the new name and sometimes it will return `purg-.....'. So the issue appears to be to do with how renaming is handled.
Update
As al_lea pointed out, the issue here was related to accommodatePresentedItemDeletionWithCompletionHandler:. Expanding on al_lea's answer, I added the code below to my UIDocument subclass. This fixed the issue.
- (void) accommodatePresentedItemDeletionWithCompletionHandler: (void (^) (NSError *errorOrNil)) completionHandler
{
PresentedDocument* presentedDocument = [self retain];
[presentedDocument closeWithCompletionHandler: ^(BOOL success) {
NSError* error = nil;
if (!success)
{
NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
#"Could not close document that is being deleted on another device",
NSLocalizedDescriptionKey, nil];
error = [NSError errorWithDomain: #"some_suitable_domain"
code: 101
userInfo: userInfo];
}
completionHandler(error); // run the passed in completion handler (required)
dispatch_async(dispatch_get_main_queue(), ^
{
[[NSNotificationCenter defaultCenter] postNotificationName: NOTIFY_presentedDocumentDeletedOnAnotherDevice
object: presentedDocument
userInfo: nil];
[presentedDocument tidyUpAfterDelete]; // app specific tidy up
[presentedDocument release];
});
}];
}
With this code in place, there are no spurious and confusing presentedItemDidMoveToURL: calls made and, in addition, the relevant object can listen for notifications of deletions on other devices.
This type of URL appears when a UIDocument is opened on local and get deleted from a remote device:
file://localhost/var/mobile/Library/Mobile%20Documents/.ubd/peer-43A0AEB6-84CE-283E-CA39-FCC4EF3BC8F8-v23/ftr/purg-
You need to close the document first before it get deleted - detect this in NSFilePresenter's accommodatePresentedItemDeletionWithCompletionHandler:

Resources