First time I am using coreBluetooth.
Here is my implementation is there any thing wrong in it.
#synthesize CM,activePeripheral;
- (id)init
{
if ((self = [super init]))
{
CM = [[CBCentralManager alloc]initWithDelegate:self queue:dispatch_get_main_queue()];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (int) scanForPeripherals
{
if (self.CM.state != CBCentralManagerStatePoweredOn)
{
NSLog(#"CoreBluetooth is %s",[self centralManagerStateToString:self.CM.state]);
return -1;
}
[self.CM scanForPeripheralsWithServices:[NSArray arrayWithObject:[CBUUID UUIDWithString:#"180D"]] options:#{CBCentralManagerScanOptionAllowDuplicatesKey: #YES}];
return 0;
}
- (const char *) centralManagerStateToString: (int)state
{
switch(state)
{
case CBCentralManagerStateUnknown:
return "State unknown (CBCentralManagerStateUnknown)";
case CBCentralManagerStateResetting:
return "State resetting (CBCentralManagerStateUnknown)";
case CBCentralManagerStateUnsupported:
return "State BLE unsupported (CBCentralManagerStateResetting)";
case CBCentralManagerStateUnauthorized:
return "State unauthorized (CBCentralManagerStateUnauthorized)";
case CBCentralManagerStatePoweredOff:
return "State BLE powered off (CBCentralManagerStatePoweredOff)";
case CBCentralManagerStatePoweredOn:
return "State powered up and ready (CBCentralManagerStatePoweredOn)";
default:
return "State unknown";
}
return "Unknown state";
}
- (void) connectPeripheral:(CBPeripheral *)peripheral {
printf("Connecting to peripheral with UUID : %s\r\n",[self UUIDToString:peripheral.UUID]);
self.activePeripheral = peripheral;
self.activePeripheral.delegate = self;
[self.CM connectPeripheral:self.activePeripheral options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey]];
}
-(const char *) UUIDToString:(CFUUIDRef)UUID
{
if (!UUID)
return "NULL";
CFStringRef s = CFUUIDCreateString(NULL, UUID);
return CFStringGetCStringPtr(s, 0);
}
#pragma mark -Central manager delegate method
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
NSLog(#"hits it");
if (central.state != CBCentralManagerStatePoweredOn) {
return;
}
isOn=YES;
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
NSLog(#"Received periferal :%#",peripheral);
NSLog(#"Ad data :%#",advertisementData);
[MBProgressHUD hideHUDForView:self.view animated:YES];
}
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
NSLog(#"Connected peripheral %#",peripheral);
}
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(#"Error occured :%#",[error localizedDescription]);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)scanDevices:(id)sender {
if (isOn) {
[MBProgressHUD showHUDAddedTo:self.view animated:YES];
[self scanForPeripherals];
}
}
Every time it gives log
CoreBluetooth is State unknown (CBCentralManagerStateUnknown)
update to question
After suggestion given by #Michael Dautermann , I come to know that my centralManagerDidUpdateState delegate method is not hitting.I dunno why this is happening.If anybody finds the reason please notify me.
Thanks you.
CoreBluetooth is simply in the process of starting up.
You need this delegate method to hit first:
- (void) centralManagerDidUpdateState: (CBCentralManager *) central;
And once it does, then you can start scanning for peripherals.
After few days, I checked out the initialization of CentralManager and I come to know that init method on firstViewController never called.I checked out by printing log in init method.
- (id)init
{
NSLog(#"hello init");
if ((self = [super init]))
{
CM = [[CBCentralManager alloc]initWithDelegate:self queue:dispatch_get_main_queue()];
}
return self;
}
- (void)viewDidLoad
{ CM = [[CBCentralManager alloc]initWithDelegate:self queue:dispatch_get_main_queue()];
isOn=NO;
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
So , I initialize the central manager in viewDidLoad and now it is initialized and centralManagerDidUpdateState finally called.Now printing CBCentralManagerStateUnsupported and that's not the issue because iPhone 4 doesn't support it.Thanks to michael help me a lot.
Where do you call scanDevices? I think you're calling it too early. You should call it inside centralManagerDidUpdateState.
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
NSLog(#"hits it");
if (central.state != CBCentralManagerStatePoweredOn) {
[self scanDevices]:
}
isOn=YES;
}
Related
I am using the following CKNotification Info and this seems to work fine:
CKNotificationInfo *note = [[CKNotificationInfo alloc] init];
note.alertBody = #"Something Happened";
note.shouldBadge = NO;
note.shouldSendContentAvailable = NO;
When something changes on an iOS device, my Mac app receives a Push notification based on a subscription with this notification. However, didReceiveRemoteNotification is never called so I can't process the event. I need to be able to refresh and fetch new changes. How do I do that?
Calling registerForRemoteNotificationTypes: and implementing didRegisterForRemoteNotificationsWithDeviceToken:
should be enough code, and the App ID should include the Push Notifications service.
I'm using CloudKit in a cross-platform (iOS/OS X) app to synchronize favorites between devices like so:
// OS X specific code
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[NSApp registerForRemoteNotificationTypes:NSRemoteNotificationTypeNone];// silent push notification!
}
- (void)application:(NSApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
[self.favCon handleCloudKitNotificationWithUserInfo:userInfo];
}
Note the usage of NSRemoteNotificationTypeNone which means silent push notification! This is how I set up CloudKit in the FavController class:
- (void)getOrCreateFavZoneWithCompletionHandler:(successCompletionHandler)handler {
// check if FavZone exists op
__block int createZone = 0;
CKFetchRecordZonesOperation *fetchRecZonesOp = [[CKFetchRecordZonesOperation alloc] initWithRecordZoneIDs:#[[FavController favRecordZoneID]]];
CKModifyRecordZonesOperation *saveRecZoneOp = [[CKModifyRecordZonesOperation alloc] initWithRecordZonesToSave:nil recordZoneIDsToDelete:nil];
fetchRecZonesOp.fetchRecordZonesCompletionBlock = ^(NSDictionary *recordZonesByZoneID, NSError *operationError) {
if (recordZonesByZoneID.count == 0) {// zone doesn't exist
createZone = 1;
CKRecordZone *favZone = [[CKRecordZone alloc] initWithZoneName:UTXAFavZoneName];
saveRecZoneOp.recordZonesToSave = #[favZone];
NSLog(#"Creating new Zone %#", favZone.zoneID.zoneName);
} else {
NSLog(#"Zone %# already exists.", [FavController favRecordZoneID].zoneName);
}
};
// create FavZone op
saveRecZoneOp.modifyRecordZonesCompletionBlock = ^(NSArray *savedRecordZones, NSArray *deletedRecordZoneIDs, NSError *operationError) {
[self successCompletionHandler:(savedRecordZones.count == createZone) error:operationError informDelegate:YES handler:handler];
};
[saveRecZoneOp addDependency:fetchRecZonesOp];
[[FavController favDatabase] addOperation:fetchRecZonesOp];
[[FavController favDatabase] addOperation:saveRecZoneOp];
}
- (void)subscribeToFavChanges:(successCompletionHandler)handler {
// get current subscription
[[FavController favDatabase] fetchSubscriptionWithID:UTXAFavConCKSubscriptionID completionHandler:^(CKSubscription *subscription, NSError *error) {
if (subscription) {
NSLog(#"using existing subscription: %#", subscription);
[self successCompletionHandler:YES error:nil informDelegate:NO handler:handler];
} else {
CKSubscription *sub = [[CKSubscription alloc] initWithZoneID:[FavController favRecordZoneID]
subscriptionID:UTXAFavConCKSubscriptionID
options:0];// "You must specify 0 for this parameter. Zone subscriptions currently do not support any options."
[[FavController favDatabase] saveSubscription:sub completionHandler:^(CKSubscription *subscription, NSError *error) {
NSLog(#"created new subscription: %# %#", subscription, error);
[self successCompletionHandler:(error == nil) error:error informDelegate:YES handler:handler];
}];
}
}];
}
As soon as I add or remove a record on one device, I'll get a notification on all other device, which I handle like so in the FavController class:
/// #abstract Handle push notifications sent by iCloud.
/// #discussion App delegates call this method when they receive a push notification through didReceiveRemoteNotification.
/// Currently, only airport favorites produce a PN, it is of type CKNotificationTypeRecordZone.
/// #param userInfo The userInfo dict tied to each push notification.
- (void)handleCloudKitNotificationWithUserInfo:(NSDictionary *)userInfo {
[self recursivelyCheckForPreviousCloudKitNotifications];
}
- (void)recursivelyCheckForPreviousCloudKitNotifications {
CKFetchNotificationChangesOperation *fetchOp = [[CKFetchNotificationChangesOperation alloc] initWithPreviousServerChangeToken:_defCon.notificationChangeToken];
__weak CKFetchNotificationChangesOperation *weakOp = fetchOp;
fetchOp.notificationChangedBlock = ^(CKNotification *notification) {
[self handleNotification:notification];
};
fetchOp.fetchNotificationChangesCompletionBlock = ^( CKServerChangeToken *serverChangeToken, NSError *operationError) {
NSLog(#"new notification change token: %#", serverChangeToken);
_defCon.notificationChangeToken = serverChangeToken;
if (weakOp.moreComing) {
NSLog(#"more coming!!");
[self recursivelyCheckForPreviousCloudKitNotifications];
} else {
NSLog(#"done handling notification changes.");
}
};
[[FavController favContainer] addOperation:fetchOp];
}
- (void)handleNotification:(CKNotification *)notification {// withCompletionHandler:(successCompletionHandler)handler {
if (notification.notificationType == CKNotificationTypeRecordZone) {// make sure we handle only zone changes
CKRecordZoneNotification *noti = (CKRecordZoneNotification *)notification;
if ([noti.recordZoneID.zoneName isEqualToString:[FavController favRecordZoneID].zoneName]) {
// received an update for the fav zone
[self queuedFavUpdateFromCloud];
} else {
// received an update for an unknown zone
NSLog(#"WARNING: received an update for an unknown zone: %#", noti.recordZoneID.zoneName);
}
} else {
NSLog(#"WARNING: received unknown notification: %#", notification);
}
}
Okay I've finally figured it out. If you use a CKNotificationInfo for your alerts, didReceiveRemoteNotification will NOT be called on the Mac until and unless you set CKNotificationInfo.soundName to an empty string! This looks like a bug only in OS X (10.10 & 10.11 so far) but can be worked around by this simple change.
I have a profile view controller where the user can set or change his or her profile picture but am getting constant errors that do not make sense to me.
-(void)getProfilePicture
{
PFUser *user = [PFUser currentUser];
NSLog(#"file--%#",[user objectForKey:PF_USER_PICTURE]);
userName = user[PF_USER_USERNAME];
status = user[PF_USER_STATUS];
if ([user objectForKey:PF_USER_PICTURE]) {
[imageUser setFile:[user objectForKey:PF_USER_PICTURE]];
[imageUser loadInBackground];
}
else{
imageUser.image = [UIImage imageNamed:#"blank_profile#2x.png"];
}
// fieldName.text = user[PF_USER_FULLNAME];
}
#pragma mark - UIActionSheetDelegate
I receive the following errors portrayed in my ProfileViewController.m (I can provide/add .h if needed):
"No visible #interface for 'UIImageView' declares the selector 'setFile:'
"No visible #interface for 'UIImageView' declares the selector 'loadInBackground'
Any help would be much appreciated or any supporting code thats needed, thanks.
Try this and see what it does for you:
-(void)getProfilePicture
{
PFUser *user = [PFUser currentUser];
NSLog(#"file--%#",[user objectForKey:PF_USER_PICTURE]);
userName = user[PF_USER_USERNAME];
status = user[PF_USER_STATUS];
if ([user objectForKey:PF_USER_PICTURE]) {
userImage.file = [user objectForKey:PF_USER_PICTURE];
[userImage loadInBackground:^(UIImage *image, NSError *error) {
if (!error) {
imageUser.image = image;
[imageUser setNeedsDisplay];
} else {
NSLog(#"%#", error);
}
}];
}
else{
imageUser.image = [UIImage imageNamed:#"blank_profile#2x.png"];
}
// fieldName.text = user[PF_USER_FULLNAME];
}
#pragma mark - UIActionSheetDelegate
This is assuming your userImage is a PFImageView and [user objectForKey:PF_USER_PICTURE] is a PFFile.
EDIT
Actually, looking at your error it seems that userImage is just a UIImageView not a PFImageView, which might be the source of all your problems. Try making the userImage a PFImageView
I've just implemented a share-button, that has a share menu:
[_shareButton sendActionOn:NSLeftMouseDownMask];
And has this action connected:
-(IBAction)share:(id)sender {
NSArray *shareArray = #[#"testShare"];
NSSharingServicePicker *sharingServicePicker = [[NSSharingServicePicker alloc] initWithItems:shareArray];
sharingServicePicker.delegate = self;
[sharingServicePicker showRelativeToRect:[sender bounds]
ofView:sender
preferredEdge:NSMinYEdge];
}
Now to my question, I don't want Facebook and Twitter to be an option in the menu. I only want E-Mail and Messages to be available. Also I would like to add "Print", but don't know if I can do that.
Is that possible?
Thanks
(Don't have enough rep points to add 'NSSharingService' as a tag)
Solved it by using proposedSharingServices.
- (NSArray *)sharingServicePicker:(NSSharingServicePicker *)sharingServicePicker sharingServicesForItems:(NSArray *)items proposedSharingServices:(NSArray *)proposedServices{
// Find and the services you want
NSMutableArray *newProposedServices = [[NSMutableArray alloc] initWithCapacity:5];
for (NSSharingService *sharingService in proposedServices) {
if ([[sharingService title] isEqualToString:#"Email"] || [[sharingService title] isEqualToString:#"Message"]) {
[newProposedServices addObject:sharingService];
}
}
NSArray *services = newProposedServices;
NSSharingService *customService = [[NSSharingService alloc] initWithTitle:#"Print" image:[NSImage imageNamed:#"PrintImage"] alternateImage:nil handler:^{
// Do whatever
}];
services = [services arrayByAddingObject:customService];
return services;
}
Comparing a proposed service to a new named instance works. Here's a trivial Swift code from my project:
let excludedNames = [
NSSharingServiceNamePostOnFacebook,
NSSharingServiceNamePostOnTwitter,
]
var excludedServices = [NSSharingService]()
for name in excludedNames {
if let service = NSSharingService(named: name) {
excludedServices += [service]
}
}
return proposedServices.filter {
!excludedServices.contains($0)
}
No need to use a private name property.
Rather then trying to say what you don't want simply return a list of what you do want.
- (NSArray<NSSharingService *> *)sharingServicePicker:(NSSharingServicePicker *)sharingServicePicker sharingServicesForItems:(NSArray *)items proposedSharingServices:(NSArray<NSSharingService *> *)proposedServices
{
NSArray *result = #[[NSSharingService sharingServiceNamed:NSSharingServiceNameComposeEmail], [NSSharingService sharingServiceNamed:NSSharingServiceNameComposeMessage]];
return result;
}
A slightly different approach via proposedSharingServices:
- (NSArray*)sharingServicePicker:(NSSharingServicePicker *)sharingServicePicker sharingServicesForItems:(NSArray *)items proposedSharingServices:(NSArray *)proposedServices {
NSArray *excludedServices = #[NSSharingServiceNamePostOnFacebook,
NSSharingServiceNamePostOnTwitter];
NSArray *sharingServices = [proposedServices filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"NOT (name IN %#)", excludedServices]];
return sharingServices;
}
Here's a better way - no private API access required.
NSArray *excludedServices = #[NSSharingServiceNamePostOnFacebook,
NSSharingServiceNamePostOnTwitter];
NSMutableArray *includedServices = [[NSMutableArray alloc] init];
for (NSSharingService *service in proposedServices) {
if ([excludedServices indexOfObject:service] == NSNotFound) {
[includedServices addObject:service];
}
}
return includedServices;
it works with no problems:
h file:
- (BOOL) trytoGETURL;
m file
- (BOOL) trytoGETURL {
/ some code here ...
if ([response statusCode] == 200)
return YES;
else
return NO;
}
- (IBAction)ButtonTouchUp:(id)sender {
NSLog(#"button clicked");
if ( [self trytoGETURL]) {
NSLog(#"ok");
} else NSLog(#"problem");
but this crashes:
h file
- (BOOL) trytoGETURL:(NSString *) baseurl Redvalue:(int)red
GreenValue:(int)green BlueValue: (int) blue;
m file
- (BOOL) trytoGETURL:(NSString *) baseurl Redvalue:(int)red
GreenValue:(int)green BlueValue: (int) blue {
if ([response statusCode] == 200)
return YES;
else
return NO;
}
- (IBAction)ButtonTouchUp:(id)sender {
NSLog(#"button clicked");
if ( [self trytoGETURL:#"sd" Redvalue:100 Greenvalue:100 Bluevalue:100]) {
NSLog(#"est takaya stranica");
} else NSLog(#"net takoi stranica");
Xcode also writes: instance method not found!??
and by the way it doesn't help me with when I'm starting to write like usual, why is it so?
Check your capitalization:
trytoGETURL:Redvalue:Greenvalue:Bluevalue:
is most certainly not the same as:
trytoGETURL:RedValue:GreenValue:BlueValue:
it was just a problem with suntax.
trytoGETURL:(NSString *) baseurl - is wrong,
trytoGETURL:(NSString *)baseurl is right. - no space needed.
I have 2 SOAP services that I want to call from an IPad app.
One is used to Log the user in (SecurityASMX), the other is one that returns the current username (SecuredCalls) once logged in.
I can call the SecurityASMX no problem using the following code. The Async call callback is operation :
- (IBAction) OnButtonClick:(id) sender {
bindingSecurity = [[SecurityASMXSvc SecurityASMXSoapBinding] initWithAddress:#"http://myserver/Azur.IPADTest.Web.Services/public/Security.asmx"];
bindingSecurity.logXMLInOut = YES;
SecurityASMXSvc_Login *requestLogin = [[SecurityASMXSvc_Login alloc] init];
requestLogin.strUsername = #"test";
requestLogin.strPassword = #"testpass";
[bindingSecurity LoginAsyncUsingParameters:requestLogin delegate:self];
[requestLogin release];
self.label.text = #"Login in progress";
}
- (void) operation:(SecurityASMXSoapBindingOperation *)operation completedWithResponse:(SecurityASMXSoapBindingResponse *)response
{
[NSThread sleepForTimeInterval:2.0];
self.label.text = #"Login Done!";
}
This works fine.
However, in the same code file, I have a binding to my second web service to return the username with the following code. The async call callback is operationSecure :
- (IBAction) OnButtonSecureCallClick:(id) sender {
bindingSecuredCalls = [[SecureCallsSvc SecureCallsSoapBinding] initWithAddress:#"http://myserver/Azur.IPADTest.Web.Services/private/SecureCalls.asmx"];
bindingSecuredCalls.logXMLInOut = YES;
SecureCallsSvc_ReturnUserName *requestReturnUserName = [[SecureCallsSvc_ReturnUserName alloc] init];
[bindingSecuredCalls ReturnUserNameAsyncUsingParameters:requestReturnUserName delegate:self];
[requestReturnUserName release];
self.label.text = #"Get UserName In Progress";
}
- (void) operationSecure:(SecureCallsSoapBindingOperation *)operation completedWithResponse:(SecureCallsSoapBindingResponse *)response
{
[NSThread sleepForTimeInterval:2.0];
self.label.text = #"Get Username Done!";
}
The problem is that when the call to ReturnUserName returns, the method that gets called is the one for the login (operation) and not the one I want (operationSecure).
How can I tell my second webservice binding to call the second callback?
Thanks!
First thing would be to check if the API you're using (I assume it's a third party API) allows you to specify the callback method.
If not, you can work with the operation parameter and use isKindOfClass to see what is actually being passed.
- (void) operation:(SecurityASMXSoapBindingOperation *)operation completedWithResponse:(SecurityASMXSoapBindingResponse *)response
{
[NSThread sleepForTimeInterval:2.0];
if([operation isKindOfClass:[SecurityASMXSoapBindingOperation class]])
{
self.label.text = #"Login Done!";
}
else if([operation isKindOfClass:[SecureCallsSoapBindingOperation class]])
{
self.label.text = #"Get Username Done!";
}
}
Ideally you'd set the type of operation and response parameters to be the superclass of the respective objects returned.