I really don't understand what's going on here.
I have a function that is getting the first 3 bytes from an NSData object, receivedStream, and putting them into another NSData object, temp, via a char array. Then comparing that to an NSData object created from a char array buffer. Both new NSData objects are created and have the correct contents. However, when isEqualtoData is called, I get an error:
[NSConcreteData isEqualtoData:]: unrecognized selector sent to instance (instance refers to tmp2)
I also get the warning
Instance method '-isEqualtoData:' not found (return type defaults to 'id')
which I don't understand as it's clear that this is a valid method in the docs. Do I need to declare NSData.h somewhere?
-(BOOL)checkHeader{
char tmp[3];
[receivedStream getBytes:&tmp length:3];
NSData *temp = [NSData dataWithBytes:tmp length:3];
NSData *tmp2 = [NSData dataWithBytes:header length:3];
BOOL test = [tmp2 isEqualtoData:temp];
return test;
}
The method is called isEqualToData:. Note the capital T – Objective-C is case-sensitive, as most programming languages.
Related
What is the difference between these two objective-c statements?
NSData *documentBytes = [NSData dataWithContentsOfFile:filePath];
versus this:
NSData *documentBytes = [NSData initWithContentsOfFile:filePath];
From Apple's NSData Class Reference page, it states the following about each
dataWithContentsOfFile - Creates and returns a data object by reading every byte from the file specified by a given path.
initWithContentsOfFile - Returns a data object initialized by reading into it the data from the file specified by a given path.
To me, these seem functionally equivalent but I highly doubt they do the same thing in all cases, right?
Thanks in advance...
-Ergin
When you use init, you always have to use alloc, like so:
NSData *documentBytes = [[NSData alloc] initWithContentsOfFile:filePath];
This returns an NSData object with a retain count of 1, you now own the reference and are responsible for releasing it.
When using dataWithContentsOfFile
NSData *documentBytes = [NSData dataWithContentsOfFile:filePath];
You get back an autoreleased NSData object. You can use it and forget about it, the autorelease pool will take care of it. If you want to store it, you have to retain it.
Of course, when you are using ARC, you can forget about all of this ;-), the methods are essentially the same.
The second
NSData *documentBytes = [NSData initWithContentsOfFile:filePath];
Will not compile you will need to alloc it first, will look something like:
NSData *documentBytes = [[NSData alloc] initWithContentsOfFile:filePath];
But one or another will work the same, in the end you will have an NSData that has the contet of the file. The first one is a shortcut.
So about your doubt:
The first one you do not need to alloc the object first, the method will return the object for you, if you are not using ARC (I do not think so), the first one will return an object that the system will take care.
The second one you will need to alloc the object first, the method only initialize your object, and if you are not using ARC you will need to take care to release it.
I'd like to copy a float into the pasteboard, but the important thing is the value, as I want to paste it later in numbers, as a number.
Tried with :
[pasteboard setValue:SomeNSNumberWhereIStoredTheFloat forPasteboardType:#"NSNumber"];
With that, it got nothing to paste, and with pasteboard.string = numberInStringValue, it pastes the number as a series of characters, in what I'm not interested.
Thanks for your help
The "type" of pasteboard data is not the name of a class, it's a Uniform Type Identifier (UTI, or just UT if you remember what else UTI stands for.) In this case, your data does not have an associated UTI (numbers are abstract concepts, not data formats.) You'll have to figure out the best way to store that number and retrieve it.
I think in this case, formatting the number into a string will suffice:
NSString *numString = [NSString stringWithFormat:#"%f", theFloatValue];
pasteboard.string = numString;
And later, when getting it back:
float theFloatValue2 = [pasteboard.string doubleValue];
This does not take into account checking for nil or other error handling.
If you need very high precision, you may need to investigate an NSData-based storage technique.
You can store an NSNumber directly. You can used the following methods from the API
setValue:forPasteboardType:
Use this method to put an object on the pasteboard that is a standard property-list object that is an object of the NSString, NSArray, NSDictionary, NSDate, NSNumber, or NSURL class.
valueForPasteboardType:
This method attempts to return an object that is of a class type appropriate to the representation type, which typically is a UTI. For example, if the representation type is kUTTypePlainText (public.plain-text), the method returns an NSString object. If the method cannot determine the class type from the representation type, it returns the object as a generic property-list object. Property-list objects include NSString, NSArray, NSDictionary, NSDate, or NSNumber objects, with NSURL objects also as a possibility. If the method cannot decode the value as a property-list object, it returns the pasteboard item as an NSData object.
The real problem comes in finding the correct UTI so the class will automatically give you back an NSNumber and not give you back an NSData object instead.
To make matters worse, the code doest not appear to work as the advertised by the documentation. I've heard from several people the method will always return you NSData. You can find an example (and a workaround) of such issue in this answer.
You can store your float value as NSNumber.
But NSNumber is not stored in UIPasteboard correctly although docs states it does (bug?).
To keep NSNumber in UIPasteboard you should archive NSNumber to NSData, and to retrieve NSNumber from UIPasteboard you should unarchive NSData back to NSNumber.
// adding data to pasteboard
NSNumber *number = [NSNumber numberWithDouble:floatValue]; // store your value here
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:number]; // archive NSNumber to NSData
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:data, #"yourKey",nil];
[[UIPasteboard generalPasteboard] addItems:[NSArray arrayWithObject:dict]];
// retrieving data
NSData *data = [dict valueForKey:#"yourKey"]; // here dict is properly obtained NSDictionary of pasteboard object
NSNumber *number = [NSKeyedUnarchiver unarchiveObjectWithData:data]; // unarchive NSData to NSNumber
How do I create an instance of NSData with an array of shorts? As I understand [NSData dataWithBytes] method expects input as an array of unsigned chars?
Thanks
dataWithBytes: takes a void *. You can pass anything you want in; just make sure you take endianness into account, if cross-architecture is an issue.
I'm using
[NSKeyedArchiver archiveRootObject:data toFile:file];
to save NSMutableArray to file. That works fine.
The problem comes when I try to get the array back.
NSMutableArray *s = [NSKeyedUnarchiver unarchiveObjectWithData:file];
Here I get
Incompatible pointer types sending NSString *__strong to parameter of type NSData
What is wrong here ?
You are trying to use unarchiveObjectWithData:, which expects you to pass it the contents of the file. Try using unarchiveObjectWithFile: instead, which expects you to pass it the filename.
NSData* arrayData = [NSData dataWithContentsOfFile:file];
NSMutableArray* s = [NSKeyedUnarchiver unarchiveObjectWithData:arrayData]
For production code, you should do some type/null checking before assuming the data is valid.
I have malloc'd a whole mess of data in an NSOperation instance. I have a pointer:
data = malloc(humungous_amounts_of_god_knows_what);
uint8_t* data;
How do I package this up as an NSData instance and return it to the main thread? I am assuming that after conversion to an NSData instance I can simply call:
free(data);
Yes?
Also, back on the main thread how do I retrieve the pointer?
Thanks,
Doug
You want one of the -dataWithBytes:length: or its variants:
NSData *d = [NSData dataWithBytes:data length:lengthOfDataInBytes];
which copies the bytes and you can then free(data). To save a copy, assuming data is allocated using malloc use:
NSData *d = [NSData dataWithBytesNoCopy:data length:lengthOfDataInBytes];
You should not call free on your buffer in this case, as the NSData instance will free it for you.
Note that all of these methods return an autoreleased instance, so you will probably have to retain it if you want to keep it around between threads (and aren't using GC). You can use the equivalent alloc/initWithBytes:... initializers instead.
To get a pointer to an NSData's contents, use bytes.
(I think a few minutes with the NSData documentation will serve you well)
Thanks Barry,
I actually went with something even simpler.
Put an NSValue wrapper around the pointer:
NSValue *value = [NSValue valueWithPointer:imageData];
Stuff it in a dictionary to be returned to the main thread:
[result setObject:value forKey:cubicFaceName];
Back on the main thread, when I'm done with the data I discard it:
uint8_t *bits = [value pointerValue];
free(bits);
Cheers,
Doug