Bluetooth Core Framework callback routine peripheralManagerIsReadyToUpdateSubscribers: isn't called - objective-c

I'm trying to figure out how to make certain callbacks trigger.
On the peripheral peripheralManager:central:didSubscribeToCharacteristic: is called correctly and it sends a chunk (first of two) of data to the central which receives it in peripheral:didUpdateValueForCharacteristic:error: as expected.
Now there's one chunk left which is supposed to be sent in the peripheral's callback peripheralManagerIsReadyToUpdateSubscribers: according to Apple's test application.
I've tested and verified and it works fine there. It's a bit fishy though as according to the docs it's only supposed to be called when the peripheral manager's updateValue:forCharacteristic:onSubscribedCentrals: fails.
How do I make the peripheral send the remaining chunk? I can supply you with code, but it's almost identical (I'm using an array of NSData chunks instead of one large NSData like the example) to the example application I linked to, I'm more curious as to how the callback chain works and what needs to be in place for the different selectors to trigger.

What you are doing is the normal way of operation. The peripheral manager handles the data sending and implements flow control according to the current settings. E.g. if you are using indications instead of notifications, then each update has to be acknowledged by the receiver before you can send again.
Notifications on the other hand are similar to UDP packets. They can get lost. To make sure that the data arrived error free, you need to implement additional control flow management.
All in all, you are doing it right.

I managed to trigger peripheralManagerIsReadyToUpdateSubscribers: by using a loop in sendData (which is called from peripheralManagerIsReadyToUpdateSubscribers: and peripheralManager:central:didSubscribeToCharacteristic:).
- (void)sendData {
BOOL success = YES;
while (success && ([_outgoingDataQueue count] > 0)) {
NSData *chunk = [_outgoingDataQueue peek];
success = [self.peripheralManager updateValue:chunk
forCharacteristic:self.characteristic
onSubscribedCentrals:nil];
if (success) {
[_outgoingDataQueue dequeue];
}
}
}
This does not feel like the correct way to send data as chunks to the central.

Related

Design suggestions for client receiving messages over network

I'm programming a client that receives a set of different messages from a server via TCP. I have created a simple test class that is able to connect to the server and receive messages in form of NSData chunks. But now I'm stuck at how to proceed from here and need some design suggestions.
One idea I have is to create a protocol that for each message, notifies the delegate with the type of message received and an object containing the message:
Protocol
-(void)didReceiveLifesign:(LifesignMessage*)message;
-(void)didReceiveLocation:(LocationMessage*)message;
...
Parser
-(void)didReceiveData:(NSData*)data {
int type = getType(data);
switch(type) {
case 0: [self.delegate didReceiveLifesign:parseLifesign(data); break;
case 1: [self.delegate didReceiveLocation:parseLocation(data); break;
...
}
}
But as the amount of messages grow I find this solution messy. Is there a prettier way of doing this?
Each time you add a new type of message to the system, you will be adding new code to handle that particular type. You cannot get away from that. So, the place you can really abstract-out right now is the dispatching: the switch statement, in your case.
If very few new message-types will be added in the future, the simplest approach may be the one you have already taken: simply add a new "case" each time.
An alternate approach is to allow other code to register as a "listener"/"callback". That makes the dispatching generic. The logic becomes:
Find the message type
Dispatch to all registered callbacks/listeners
The new "problem" would be: you will now need to register each listener at some point. This would be sdone during some type of initialization. it may not be worth it if your message dispatcher is basically part of the overall app, and is not to be used elsewhere.

What to do when users generate the same action several time waiting for download?

I am designing an IPhone application. User search something. We grab data from the net. Then we update the table.
THe pseudocode would be
[DoThisAtbackground ^{
LoadData ();
[DoThisAtForeground ^{
UpdateTableAndView();
}];
}];
What about if before the first search is done the user search something else.
What's the industry standard way to solve the issue?
Keep track which thread is still running and only update the table
when ALL threads have finished?
Update the view every time a thread finish?
How exactly we do this?
I suggest you take a look at the iOS Human Interface Guidelines. Apple thinks it's pretty important all application behave in about the same way, so they've written an extensive document about these kind of issues.
In the guidelines there are two things that are relevant to your question:
Make Search Quick and Rewarding: "When possible, also filter remote data while users type. Although filtering users' typing can result in a better search experience, be sure to inform them and give them an opportunity to opt out if the response time is likely to delay the results by more than a second or two."
Feedback: "Feedback acknowledges people’s actions and assures them that processing is occurring. People expect immediate feedback when they operate a control, and they appreciate status updates during lengthy operations."
Although there is of course a lot of nonsense in these guidelines, I think the above points are actually a good idea to follow. As a user, I expect something to happen when searching, and when you update the view every time a thread is finished, the user will see the fastest response. Yes, it might be results the user doesn't want, but something is happening! For example, take the Safari web browser in iOS: Google autocomplete displays results even when you're typing, and not just when you've finished entering your search query.
So I think it's best to go with your second option.
If you're performing the REST request for data to your remote server you can always cancel the request and start the new one without updating the table, which is a way to go. Requests that have the time to finish will update UI and the others won't. For example use ASIHTTPRequest
- (void)serverPerformDataRequestWithQuery:(NSString *)query andDelegate:(__weak id <ServerDelegate)delegate {
[currentRequest setFailedBlock:nil];
[currentRequest cancel];
currentRequest = [[ASIHTTPRequest alloc] initWithURL:kHOST];
[currentRequest startAsynchronous];
}
Let me know if you need an answer for the local SQLite databases too as it is much more complicated.
You could use NSOperationQueue to cancel all pending operations, but it still would not cancel the existing operation. You would still have to implement something to cancel the existing operation... which also works to early-abort the operations in the queue.
I usually prefer straight GCD, unless there are other benefits in my use cases that are a better fit for NSOperationQueue.
Also, if your loading has an external cancel mechanism, you want to cancel any pending I/O operations.
If the operations are independent, consider a concurrent queue, as it will allow the newer request to execute simultaneously as the other(s) are being canceled.
Also, if they are all I/O, consider if you can use dispatch_io instead of blocking a thread. As Monk would say, "You'll thank me later."
Consider something like this:
- (void)userRequestedNewSearch:(SearchInfo*)searchInfo {
// Assign this operation a new token, that uniquely identifies this operation.
uint32_t token = [self nextOperationToken];
// If your "loading" API has an external abort mechanism, you want to keep
// track of the in-flight I/O so any existing I/O operations can be canceled
// before dispatching new work.
dispatch_async(myQueue, ^{
// Try to load your data in small pieces, so you can exit as early as
// possible. If you have to do a monolithic load, that's OK, but this
// block will not exit until that stops.
while (! loadIsComplete) {
if ([self currentToken] != token) return;
// Load some data, set loadIsComplete when loading completes
}
dispatch_async(dispatch_get_main_queue(), ^{
// One last check before updating the UI...
if ([self currentToken] != token) return;
// Do your UI update operations
});
});
}
It will early-abort any operation that is not the last one submitted. If you used NSOperationQueue you could call cancelAllOperations but you would still need a similar mechanism to early-abort the one that is currently executing.

In iOS does either NSURL or NSXML span a new thread?

I have a program that progresses as follows. I call a method called getCharacteristics. This method connects to a remote server via a NSURL connection (all networking code done in another file) and when it receives a response it makes a method call back to the original class. This original class then parses the data (xml) and stores its contents as a map.
The problem I'm having is that it appears that somewhere in this transaction another thread is being spawned off.
Here is sample code showing what I'm doing:
#property map
- (void) aMethod
{
[[WebService getSingleton] callWebService: andReportBackTo: self]
Print "Ready to Return"
return map;
}
- (void) methodThatIsReportedBackToAfterWebServiceRecievesResponse
{
//Parse data and store in map
Print "Done Parsing"
}
The problem that I am running into is that map is being returned before it can be fully created. Additionally, "Ready to Return" is being printed before "Done parsing" which suggests to me that there are multiple threads at work. Am I right? If so, would a simple lock be the best way to make it work?
NSURLConnection will execute in another thread if you tell it to execute asynchronously.
In my opinion the best way to deal with this would be to write your own delegate protocol, and use delegation to return your map when the you have downloaded and parsed your data.
You could retrieve your data synchronously using NSURLConnection, but you may force the user to wait for an extended period of time especially if a connection timeout occurs. I would avoid this approach.

NSURLConnection vs. NSData + GCD

NSData has always had a very convenient method called +dataWithContentsOfURL:options:error:. While convenient, it also blocks execution of the current thread, which meant it was basically useless for production code (Ignoring NSOperation). I used this method so infrequently, I completely forgot that it existed. Until recently.
The way I've been grabbing data from the tubes is the standard NSURLConnectionDelegate approach: Write a download class that handles the various NSURLConnectionDelegate methods, gradually build up some data, handle errors, etc. I'll usually make this generic enough to be reused for as many requests as possible.
Say my typical downloader class runs somewhere in the ballpark of 100 lines. That's 100 lines to do asynchronously what NSData can do synchronously in one line. For more complexity, that downloader class needs a delegate protocol of its own to communicate completion and errors to its owner, and the owner needs to implement that protocol in some fashion.
Now, enter Grand Central Dispatch, and I can do something as fantastically simple as:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
NSData* data = [NSData dataWithContentsOfURL:someURL];
// Process data, also async...
dispatch_async(dispatch_get_main_queue(), ^(void) {
// Back to the main thread for UI updates, etc.
});
});
And I can throw that sucker in anywhere I want, right in-line. No need for a download class, no need to handle connection delegate methods: Easy async data in just a few lines. The disparity between this approach and my pre-GCD approach is of a magnitude great enough to trigger the Too Good to be True Alarm.
Thus, my question: Are there any caveats to using NSData + GCD for simple data download tasks instead of NSURLConnection (Assuming I don't care about things like download progress)?
You are losing a lot of functionality here:
Can't follow the download progression
Can't cancel the download
Can't manage the possible authentication process
You can't handle errors easily, which is really important especially in mobile development like on iPhone of course (because you often lose your network in real conditions, so it is very important to track such network error cases when developing for iOS)
and there's probably more I guess.
The right approach for that is to create a class than manages the download.
See my own OHURLLoader class for example, which is simple and I made the API to be easy to use with blocks:
NSURL* url = ...
NSURLRequest* req = [NSURLRequest requestWithURL:url];
OHURLLoader* loader = [OHURLLoader URLLoaderWithRequest:req];
[loader startRequestWithCompletion:^(NSData* receivedData, NSInteger httpStatusCode) {
NSLog(#"Download of %# done (statusCode:%d)",url,httpStatusCode);
if (httpStatusCode == 200) {
NSLog(%#"Received string: %#", loader.receivedString); // receivedString is a commodity getter that interpret receivedData using the TextEncoding specified in the HTTP response
} else {
NSLog(#"HTTP Status code: %d",httpStatusCode); // Log unexpected status code
}
} errorHandler:^(NSError *error) {
NSLog(#"Error while downloading %#: %#",url,error);
}];
See the README file and sample project on github for more info.
This way:
you still rely on the asynchronous methods provided by NSURLConnection (and as the Apple's documentation says about Concurrency Programming if an API already exists to make asynchronous tasks, use it instead of relying on another threading technology if possible)
you keep advantages of NSURLConnection (error handlings, etc)
but you also have the advantages of the blocks syntax that makes your code more readable than when using delegate methods
WWDC 2010 Session Videos:
WWDC 2010 Session 207 - Network Apps for iPhone OS, Part 1
WWDC 2010 Session 208 - Network Apps for iPhone OS, Part 2
The lecturer said
"Threads Are Evil™".
For network programming, it is strongly recommended to use asynchronous API with RunLoop.
Because, if you use NSData + GCD like the following, it uses one thread per connection.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
NSData* data = [NSData dataWithContentsOfURL:someURL];
And it's likely to use many connections and many threads. It is too easy to use GCD :-)
Then, many threads eats huge amount of memory for its stack.
Thus, you'd better to use asynchronous API as AliSoftware said.
As of OS X v10.9 and iOS 7 the preferred way is to use NSURLSession. It gives you a nice, block-based interface and features like canceling, suspending and background downloading.

How to define a communication protocol?

I'm new to networking concepts and need an explaination of how to implement a communication protocol for sending different types of messages. I'm currently working on a Cocoa app that will send video messages between iPhones. Currently I only send messages of type 3. Here's the app flow I need to implement:
Browsing for available iPhones on the network (using Bonjour)
When an iPhone client is found, send NSData "request contact info" (MessageType1)
iPhone client will send back an NSData instance with contact info (MessageType2)
Init a new message with recorded video, send to selected contact (MessageType3)
When the different types of message are received, they will need to be handled differently. I guess one way to solve it is to add a header to the message that identify the message type and extract this on the receiver's side, then handle like this:
if (messageType == 1) // MessageType1
[self sendMyContactInfo:(Contact *)ownInfo];
if (messageType == 2) // MessageType2
[self updateViewWithContactInfo:(Contact *)contactInfo];
if (messageType == 3) // MessageType3
[self sendMessageToSelectedContact:(Message *)message]
For creating a message for MessageType3, I'll do this:
/* Not currently implemented */
NSMutableData *data = [[NSMutableData alloc] init];
int messageType = 3;
[data appendBytes:messageType]
/* Already Implemented */
NSData *encodedMessage = [NSKeyedArchiver archivedDataWithRootObject:message];
[data appendData:encodedMessage];
[self sendMessage:(NSData *)encodedMessage];
Is this a nice way of doing it? If so, should the protocol rules be defined in a more formal way, e.g. in a separate class or something? I'm looking for the best overall solution here, so don't take too much notice of my drawings if there's a better way to do it...
Is this a nice way of doing it?
It's a standard way for defining a communications protocol. From the Wikipedia article:
Digital message bitstrings are exchanged. The bitstrings are divided in fields and each field carries information relevant to the protocol. Conceptually the bitstring is divided into two parts called the header area and the data area. The actual message is stored in the data area, so the header area contains the fields with more relevance to the protocol. The transmissions are limited in size, because the number of transmission errors is proportional to the size of the bitstrings being sent. Bitstrings longer than the maximum transmission unit (MTU) are divided in pieces of appropriate size. Each piece has almost the same header area contents, because only some fields are dependent on the contents of the data area (notably CRC fields, containing checksums that are calculated from the data area contents).
End Wikipedia quote
If so, should the protocol rules be defined in a more formal way, e.g. in a separate class or something?
That's up to you. It's not necessary, since your application is communicating with other copies of your application.