Appending data to a string without losing previous data - ios

I have this is on the top of my program:
#property (strong, nonatomic) NSMutableData *data;
I thought this would allow me to store the value from every time this method runs:
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests
{
for (CBATTRequest *request in requests) {
NSString *stringValue = [[NSString alloc] initWithData: [request value] encoding:NSUTF8StringEncoding];
// Have we got everything we need?
if ([stringValue isEqualToString:#"EOM"]) {
// We have, so show the data,
[self.textview setText:[[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding]];
}
// Otherwise, just add the data on to what we already have
[self.data appendData:[request value]];
}
}
This method waits for a write request to be received and stores the value in a string. I have a core bluetooth central that is sending three blocks of data. This is to get around the data transfer size restriction within bluetooth LE. The problem is I can't get the three values stored. I am trying to not just store the last value but add the new value to the end of a nsstring or nssdata every time the method is called. Any help would be greatly appreciated. I thought the property at the top would allow me to do it but it either only stores the last value or nothing at all. I am not used to the ways of objective c yet. Thanks.
Even this doesn't write anything to self.data:
NSString * result = [[requests valueForKey:#"value"] componentsJoinedByString:#""];
NSData* data = [result dataUsingEncoding:NSUTF8StringEncoding];
[self.data appendData:data];
// Log it
NSLog(#"%#",self.data);

You should use NSMutableArray instead of NSString as a mutable string.
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests
{
NSMutableString *stringValue = [[NSMutableString alloc] init];
for (CBATTRequest *request in requests) {
[stringValue appendString:[[NSString alloc] initWithData:[request value] encoding:NSUTF8StringEncoding]];
// Have we got everything we need?
if ([stringValue isEqualToString:#"EOM"]) {
// We have, so show the data,
[self.textview setText:[[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding]];
}
// Otherwise, just add the data on to what we already have
[self.data appendData:[request value]];
}

Remember kids when dealing with NSMutableData always initialize it!
_data = [[NSMutableData alloc] init];
This fixed the null problem for me.

Related

Corruption of NSString or encoding issue in Objective C

Please see code below:
+ (void)splashDataFromJSON:(NSData *)objectNotation error:(NSError **)error
{
NSError *localError = nil;
NSDictionary *parsedObject = [NSJSONSerialization JSONObjectWithData:objectNotation options:0 error:&localError];
if (localError != nil) {
*error = localError;
}
NSMutableArray* btms = [[NSMutableArray alloc] init];
NSMutableDictionary* btmManufacturerResolutionDictionary = [[BTMCache sharedManager] btmManufacturerResolutionDictionary];
NSArray *results = [parsedObject valueForKey:#"results"];
NSLog(#"Count %d", parsedObject.count);
NSString* imageBaseUrl = [[parsedObject valueForKey:#"general"] valueForKey:#"image_base_url"];
imageBaseUrl = [imageBaseUrl stringByAppendingString:#"hdpi/"];
NSString* splashImageName = [[[parsedObject valueForKey:#"general"] valueForKey:#"splash"] valueForKey:#"img"];
NSString* splashAdvertiserURL = [[[[parsedObject valueForKey:#"general"] valueForKey:#"splash"] valueForKey:#"url"] copy];
NSMutableString* appendedString = [[NSMutableString alloc] init];
for(int i =0 ;i<[splashAdvertiserURL length]; i++) {
char character = [splashAdvertiserURL characterAtIndex:i];
printf(&character);
sleep(0.1);
if (character != "!")
{
[appendedString appendFormat:#"%c", character];
}
}
[[SplashData sharedManager] setSplashAdvertiserURL:appendedString];
[[SplashData sharedManager] setSplashImageName:splashImageName];
splashAdvertiserURL = [[SplashData sharedManager] splashAdvertiserURL];
}
The point of interest is in splashAdvertiserURL. When I receive this data and print it out using po, it comes out as "https://radar.com/ref/go/84/". This is fine and what was expected. When I look at the incoming data in JSONLint it looks like this:
"general": {
"image_base_url": "https:\/\/radar.com\/img\/manufacturers\/",
"splash": {
"img": "image1.png",
"url": "https:\/\/radar.com\/ref\/go\/84\/"
}
},
As you can see, further on I put the NSString into a singleton with an NSString property. Nothing abnormal here. I then proceed to retrieve it to see that all is ok. Further to this the program continues. In another class I wish to retrieve this information, and when I try and do that, it throws EXC_BAD_ACCESS. There appears to be garbage in there.
I then put in a loop in the code as you can see to print out the characters one at a time. Very curiously, when I print that out using po I get:
https://
r
a
d
ar.com/ref/go/8 4!/"
Exactly in that format. If I then proceed to hardcode the string https://radar.com/ref/go/84/ - including escape characters and everything, then all works fine. No issues. If I handle a normal string incoming without escape characters it stores fine in the singleton as well, no issue. enter code here
I am pretty stumped here as to what is going on. Can someone assist?
Thank you
For URL you received as string you need to encode before use it to in your app. Have a look at below code:
NSString *sampleUrl = #"https:\/\/radar.com\/ref\/go\/84\/";
NSString *encodedUrl = [sampleUrl stringByAddingPercentEscapesUsingEncoding:
NSUTF8StringEncoding];

Getting write request value from NSArray with Core Bluetooth

I have a method here:
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests
{
NSLog(#"PERIPHERAL: peripheralManager:%# didReceiveWriteRequests:%#", peripheral, requests);
NSString * result = [[requests valueForKey:#"description"] componentsJoinedByString:#""];
_label.text = result;
}
I receive the write request in an NSArray. Right now I am just converting the full array into a string and outputting the string into a text box. To make sure everything is set up correctly. It indeed is working, but I do not want the full array listed but just the value alone stored in a NSString.
I want this in a string:
Test
Not this:
CBATTRequest: 0x1702240 Central = , Characteristic = , Offset = 0, Value = test
This should be easy to accomplish and I am possibly just brain dead from a long day. How is this supposed to be done?
You need to consider that requests is an array of CBATTRequests, which have a value property containing an NSData object representing the data being written.
If you want one string representing all of the values, you need to iterate over requests and convert each of these NSData values to NSString and concatenate them. If I'm understanding your question correctly, this should be what you're looking for.
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests {
NSMutableString *output = [[NSMutableString alloc] init];
for (CBATTRequest *request in requests) {
NSString *stringValue = [[NSString alloc] initWithData:[request value] encoding:NSUTF8StringEncoding];
if (stringValue) {
[output appendString:stringValue];
}
}
_label.text = output.copy;
}
As a note, updating to Xcode 7 would help make this more clear, since the requests parameter of -peripheralManager:didReceiveWriteRequests: has updated to use Objective-C generics, and now has the type NSArray<CBATTRequest *> *.

PHAdjustmentData is nil in "startContentEditingWithInput"

I'm working on a photo-editing extension app, and I want it to be able to save the information about the changes made into the PHAdjustmentData, so that user can modify those changes later. I save all the required data into PHAdjustmentData, however, next time I edit the image - PHAdjustmentData is nil.
Here is a sample code:
#property (strong, nonatomic) PHContentEditingOutput *output;
- (void)startContentEditingWithInput:(PHContentEditingInput *)contentEditingInput placeholderImage:(UIImage *)placeholderImage
{
self.output = [[PHContentEditingOutput alloc] initWithContentEditingInput:contentEditingInput];
// here contentEditingInput.adjustmentData is always nil
}
- (void)finishContentEditingWithCompletionHandler:(void (^)(PHContentEditingOutput *))completionHandler
{
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:#"value1" forKey:#"key1"];
[dict setObject:#"value2" forKey:#"key2"];
NSData *adjData = [NSKeyedArchiver archivedDataWithRootObject:dict];
PHAdjustmentData *phAdjData = [[PHAdjustmentData alloc] initWithFormatIdentifier:#"ident" formatVersion:#"1.0" data:adjData];
self.output.adjustmentData = phAdjData;
NSData *data = UIImageJPEGRepresentation(result, 1.0);
[data writeToURL:self.output.renderedContentURL options:NSDataWritingAtomic error:nil];
completionHandler(self.output);
}
How do I save the adjustment data properly, so that I can access it next time user edits the image? Thanks!
PhotoKit gives you adjustment data in startContentEditingWithInput only if you've agreed to handle that data. You agree by implementing canHandleAdjustmentData to check the format identifier and version of the adjustment and then return true for formats you can handle.
If you return false from canHandleAdjustmentData, then you'll get a nil adjustment data in startContentEditingWithInput. Not only that, you'll also get a pre-edited version of the photo image, so you can't work off of how it looked before the last edit.

In XML file, i have this symbol "&amp" in an element in iOS [duplicate]

This question already has answers here:
Converting & to & in Objective-C [duplicate]
(4 answers)
Closed 9 years ago.
In XML File, i have this symbol in middle of element like below showing code.
<title>CHAIRMAN BOB LIEBER INTERVIEWED BY CITY & STATE</title>
once i read this content, i will get STATE only. So how to solve this issue to get like this, CHAIRMAN BOB LIEBER INTERVIEWED BY CITY & STATE
I had same issue in my application
NSString* contents = [NSString stringWithContentsOfURL:[NSURL
URLWithString:LINK_EVENTS_XML]
encoding:NSUTF8StringEncoding
error:nil];
// You can pre-process(replace certain characters, ...) content of xml in here.
NSData* xml = [contents dataUsingEncoding:NSUTF8StringEncoding];
NSXMLParser *nsXmlParser = [[NSXMLParser alloc] initWithData:data];
// create and init our delegate
XMLParser *parser = [[XMLParser alloc] initXMLParser];
// set delegate
[nsXmlParser setDelegate:parser];
// parsing...
BOOL success = [nsXmlParser parse]; if (success)
{
NSLog(#"No errors - event count : %i", [parser.events count]);
// get array of users here
// NSMutableArray *users = [parser users];
self.eventsArray= parser.events;
[self.tblEvents reloadData];
}
else
{
NSLog(#"Error parsing document!");
}
I figured it had something to do with encoding.
I Found answer by myself just append the strings.
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (!currentStringValue)
{
currentStringValue = [[NSMutableString alloc] init];
}
else
{
[currentStringValue appendString: [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
}
}

NSThread Causing memory Leaks in iPhone

I am uploading images chunk wise, in a background thread, each chunk will be size of 512kb,to the best of my knowledge,i have taken care of memory leaks using release,nsautoreleasepool.
Below is the code for uploading images chunkwise.
- (void)FetchDataFromDB : (NSNumber *) isOffline
{
#autoreleasepool {
#try {
NSLog(#"FetchDatafromDB");
isThreadStarted = YES;
VYukaDBFunctions *vdb = [VYukaDBFunctions getInstance];
NSMutableArray *fileNames = [vdb GetFileNames:[isOffline integerValue]];
for(int j=0 ; j<[fileNames count] ; j++)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString * filename = fileNames [j] ;
int _outgoingMsgId = [[vdb SelectMsgId:filename] intValue];
int _totalchunk =[[vdb SelectTotalChunk:filename]intValue];
int currentChunk = [vdb GetCurrentChunk:filename];
for( int i=currentChunk ; i <= _totalchunk ; i++)
{
NSAutoreleasePool *innerPool = [[NSAutoreleasePool alloc] init];
NSString *AsyncRequest = [[NSString alloc] init];
AsyncRequest = [vdb SelectAsyncRequest: i : _outgoingMsgId];
if(![AsyncRequest isEqual:#""])
{
BOOL status = [self UploadChunkWise :AsyncRequest : 1 : i : vdb : filename : _outgoingMsgId];
// AsyncRequest = NULL;
// [AsyncRequest release];
if(status){
if(i==_totalchunk)
{
NSLog(#"Deleting from medialist , FileName :%#", filename);
[vdb DeleteFromMediaList : filename];
}
}
else{
[vdb DeleteFromMediaList : filename];
break;
}
}
[innerPool drain];
}
[pool drain];
}
[fileNames removeAllObjects];
// [fileNames release];
//recurssive call to check any pending uploads..
if([[vdb GetFileNames:[isOffline integerValue]] count] > 0)
{
NSLog(#"Calling Recursively..");
[self FetchDataFromDB:[isOffline integerValue]];
}
}
#catch (NSException *exception) {
NSLog(#"Exception caught on Uploading from FetchDataFromDB:%#", exception);
}
#finally {
}
}
NSLog(#"thread quit ");
isThreadStarted = NO;
[NSThread exit];
}
-(BOOL) UploadChunkWise :(NSString *) AsyncRequest : (int) count : (int)currentChunk : (VYukaDBFunctions * ) vdb : (NSString *) currentFileName : (int) outgoingMsgId
{
NSHTTPURLResponse *response ;
NSError *error;
//Yes, http
NSMutableURLRequest *httpRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"Url goes here"]];
NSData* data = [AsyncRequest dataUsingEncoding:NSUTF8StringEncoding];
[httpRequest setHTTPMethod:#"POST"];
[httpRequest setHTTPBody:data];
[httpRequest setValue:#"application/xml" forHTTPHeaderField:#"Content-Type"];
NSData *returnedData = [NSURLConnection sendSynchronousRequest: httpRequest returningResponse:&response error:&error] ;
NSString *result= [[NSString alloc] initWithData:returnedData encoding:NSASCIIStringEncoding];
[httpRequest release];
returnedData= NULL;
[returnedData release];
data = NULL;
[data release];
if ([result rangeOfString:#"success"].location != NSNotFound )
{
NSLog(#" success");
[vdb DeleteCurrentChunkFromOutgoingTable:currentChunk : outgoingMsgId];
[result release];
return YES ;
}
else if ([result rangeOfString:#"fail"].location != NSNotFound )
{
[result release];
if (count < 3) {
return [self UploadChunkWise :AsyncRequest : count+1 : currentChunk: vdb : currentFileName : outgoingMsgId ];
}
else
{
NSLog(#" failed");
[vdb DeleteAllCurrentFileChunksFromOutgoingTable:currentFileName];
return NO ;
}
}
return NO;
}
I am starting thread as below
[NSThread detachNewThreadSelector:#selector(FetchDataFromDB:) toTarget:self withObject:[NSNumber numberWithInt:0]];
The problem is after uploading 9 to 12 chunks, i am getting memory error. i am getting 4 to 5 times memory warning and after that app crashes.in console i am getting memory warning first at app delegate class, followed by 4 classes which are extending UIViewController. why i am getting warning at app delegate, and other classes which is of type UIViewController.Why i have to release object of other class if the separate thread is giving me memory error? what i am doing wrong here? I cannot use ARC, as i have integrated this with old code, which is not using ARC, i tried enabling ARC class wise, but it dint work. Can any one help me to find out if there is any memory leaks in this code. Suggestions are welcomed and appreciated.Thanks in advance..
Two things- first, I see this:
NSString *AsyncRequest = [[NSString alloc] init];
AsyncRequest = [vdb SelectAsyncRequest: i : _outgoingMsgId];
This should be consolidated to this:
NSString *asyncRequest = [vdb SelectAsyncRequest: i : _outgoingMsgId];
You instead are creating a new instance, then immediately either generating or referencing another instance.
Second:
Your code is very hard to read and doesn't follow the Objective-C smalltalk conventions.
Variable names should begin with a lowercase letter. Method names should also start with lowercase letters. Class names and functions should begin with capital letters. It makes it difficult to read because I and many others have been trained to see capital letters and think CLASS NAME instead of POSSIBLE VARIABLE NAME. Just FYI
Finally, some of your methods take multiple parameters, like the one above. You really should add a prefix to each parameter so that it's easy to understand what the parameter is for. This:
[vdb SelectAsyncRequest: PARAMETER : PARAMETER];
would look much better if it was :
[vdb selectAsyncRequestForParameter: PARAMETER withOtherParameter:OTHERPARAM];
EDIT: I also don't think you need so many autorelease pools. The entire thing is wrapped in a big autorelease pool already.
EDIT2: I also see a lot of release calls that aren't necessary. In your UploadChunkWise method you are calling release on *data and *returnedData which are both already implicitly autoreleased. Methods that return objects to you will already have ownership given up and "handed over" to you. Essentially, those methods will do this:
NSData *data = [[NSData alloc] init];
return [data autorelease];
When you get it, if you want to keep it you will have to retain it yourself, otherwise it will be destroyed at the return of your method.
However, it is correct for you to call release on the NSString *result instance you created with -init.

Resources