I am unable to save numeric values to coredata via a bound tableview and arrayController. I have changed the code to return hardcoded values, it doesn't crash when i try edit the numeric column but doesn't persist the hardcoded value:
#import "StringToNumberTransformer.h"
#implementation StringToNumberTransformer
+ (Class)transformedValueClass { return [NSNumber class]; }
+ (BOOL)allowsReverseTransformation { return YES; }
- (id)transformedValue:(id)value {
// return (value == nil) ? nil : [NSString stringWithFormat:#"%i", [value shortValue ]];
//return (value == nil) ? nil : NSStringFromClass([value class]);
return #"1";
}
- (id)reverseTransformedValue:(id)value {
// return [value numberFromString:[value stringValue]];
return [NSNumber numberWithInt:2];
}
#end
Here is the link to the xib setup ! http://tinypic.com/r/2nty41s/5 !
Can anyone shed some light on this?
Many thanks
As stated in the docs for Custom Value Transformers (Value Transformer Programming Guide)
A value transformer subclass must implement the transformedValueClass
class method. This method returns the class of the object that the
transformedValue: method returns.
Thus, your transformedValueClass returns the class for NSNumber, but your transformedValue: method returns an instance of type NSString
Since you're converting from an NSString to an NSNumber, I imagine you'll want to swap the implementations of your transformedValue: and reverseTransformedValue: methods.
Related
I'm working on a react-native project that requires some native modules. One of them is a Bluetooth module that allows me to access some CSRGaia methods. Ultimately, I want to be able to read the eq values on the PS-key so that I can set my equalizer to the corresponding values. I know almost nothing about Objective-C
Currently there is a method that looks like this:
RCT_EXPORT_METHOD(setEQValues:(NSArray *)values callback:(RCTResponseSenderBlock)callback)
{
CSRPeripheral *connectedPeripheral = [CSRConnectionManager sharedInstance].connectedPeripheral;
if( connectedPeripheral == nil )
{
callback(#[DISCONNECTED]);
return;
}
[[CSRGaia sharedInstance] setEQValues:values];
}
This works with no issues. However, when I tried to write my own
RCT_EXPORT_METHOD(getUserEQ: (NSArray *)values callback:(RCTResponseSenderBlock)callback)
{
CSRPeripheral *connectedPeripheral = [CSRConnectionManager sharedInstance].connectedPeripheral;
if( connectedPeripheral == nil)
{
callback(#[DISCONNECTED]);
return;
}
[[CSRGaia sharedInstance] getUserEQ: values];
}
I get the following error:
No visible #interface for 'CSRGaia' declares the selector 'getUserEQ:'
I double checked the CSRGaia.m file to verify that both methods exist.
- (void)setEQValues:(NSArray *)values {
NSMutableData *payload = [[NSMutableData alloc] init];
for( NSNumber *value in values ) {
uint8_t hex = [value unsignedCharValue];
[payload appendBytes:&hex length:1];
}
[self sendCommand:GaiaCommand_SET_HEP_EQ_PSKEY
vendor:CSR_GAIA_VENDOR_ID
data:payload];
}
- (void)getUserEQ {
[self sendCommand:GaiaCommand_GetUserEQControl
vendor:CSR_GAIA_VENDOR_ID
data:nil];
}
you are calling this method:
'getUserEQ:'
notice the 2 dots colon
it's different from method
'getUser'
with no colon
and in your .m file there is only
- (void)getUserEQ {}
i guess you wanted to use the setter method, instead
- (void)setEQValues:(NSArray *)values{}
like this:
[[CSRGaia sharedInstance] setEQValues: values];
add anyway both
- (void)getUserEQ;
- (void)setEQValues:(NSArray *)values;
in CSRGaia.h file
between
#interface OSRGaia
and
#end
What would be "if let" equivalent in Objective C? The example snippet I want to convert to Objective C is below;
if let pfobjects = images as? [PFObject] {
if pfobjects.count > 0 {
var imageView: PFImageView = PFImageView()
imageView.file = pfobjects[0] as! PFFile
imageView.loadInBackground()
}
}
There's no direct equivalent to if let in Objective-C, because if let does Swift-specific things (unwrapping optionals and rebinding identifiers) that don't have direct equivalents in Objective-C.
Here's a nearly equivalent of your Swift code:
if (images != nil) {
NSArray<PFObject *> *pfobjects = (id)images;
if (pfobjects.count > 0) {
PFImageView *imageView = [[PFImageView alloc] init];
assert([pfobjects[0] isKindOfClass:[PFFile class]]);
imageView.file = (PFFile *)pfobjects[0];
[imageView loadInBackground];
}
}
But this Objective-C code won't verify that images only contains instances of PFObject, and should successfully create an image view as long as pfobjects[0] is a PFFile. Your Swift code will do nothing (create no image view) if images contains any non-PFObject elements.
You can use NSPredicate to verify the array contains only instances of PFObject:
NSPredicate *p = [NSPredicate predicateWithFormat:#"self isKindOfClass: %#", [PFObject class]];
NSInteger numberThatArePFObjects = [images filteredArrayUsingPredicate:p].count;
if(numberThatArePFObjects && numberThatArePFObjects == images.count){
// certain that images only contains instances of PFObject.
}
If however you weren't working with an array but a single object then it is simpler:
if([image isKindOfClass:[PFObject class]]){
// certain that image is a valid PFObject.
}
Or if you wanted a new variable:
PFObject* obj = nil;
if([image isKindOfClass:[PFObject class]] && (obj = image)){
// certain that obj is a valid PFObject.
}
You can use something like this:
NSArray<PFObject *> *pfobjects;
if ([images isKindOfClass: [NSArray<PFObject> class]] && (pfobjects = images)) {
// your code here
}
You want three things simultaneously. Let's split them:
variable as? OtherType is possible, but erases type, because it returns id. Implementation is as easy as a category on NSObject class, so it becomes NSArray *array = [jsonDict[#"objects"] ifKindOfClass:NSArray.class].
Implementation
#interface NSObject (OptionalDowncast)
- (id)ifKindOfClass:(__unsafe_unretained Class)clazz;
#end
#implementation NSObject (OptionalDowncast)
- (id)ifKindOfClass:(__unsafe_unretained Class)clazz {
return [self isKindOfClass:clazz] ? self : nil;
}
#end
if let is also possible in Objective-C if type is known, so it cannot be combined with previous thing. Easiest way is: for(NSArray *array = [self getItems]; array != nil; array = nil) { ... }, but if you want to use else branch, it gets a bit more complex. I have made SwiftyObjC pod for that, please take a look
Check generic template is not possible during type cast in Objective-C, thus you can cast to NSArray, but you can't cast to NSArray<PFObject>
I don't see iterations over your array: With all that being said, I think best example is (assuming images is an array already):
for(PFFile *file = [images.firstObject ifKindOfClass:PFFile.class]; file != nil; file = nil) {
imageView.file = file;
[imageView loadInBackground];
}
If you need to also iterate over it:
for(id object in images) {
for(PFFile *file = [object ifKindOfClass:PFFile.class]; file != nil; file = nil) {
//operate on file
}
}
You can use Objective-C++ in place of Objective-C. In this you can use the next define:
#define let const auto
Note: it is not the same exactly (Swift has wrapped values, ...) but it makes the work easier.
And through of this define you can use it of this way:
if (let pfobjects = images) {
if (pfobjects.count > 0 {
let imageView = [[PFImageView alloc] init];
imageView.file = pfobjects[0];
imageView loadInBackground();
}
}
To convert your Objective-C class in Objective-C++ class you only must change the extension of implementation file of .m to .mm
In Interface Builder I’ve created a textfield and stuck an NSNumberFormatter into the cell. However, the user can still type text into the textfield. Is there any way to restrict the input to numbers only using interface builder? I thought that was the point of the NSNumberFormatter.
Every formatter has this method:
- (BOOL) getObjectValue: (id*) object forString: (NSString*) string
errorDescription: (NSError**) error;
This is valid for every formatter.
If the string is not valid it returns false and the object passed as argument (dereferenced) will be nil.
So instead of dropping a number formatter to the text field, use your own formatter as instance variable.Observe the text field implementing the delegate protocol so that at every change of the text you can be notified.
Then invoke this method:
NSNumber* number;
BOOL success=[formatter getObjectValue: &number forString: [myTextField stringValue] errorDescription:nil];
At this point if success is false (or check if number is nil), there is an invalid string in the text field, so do the action that is more appropriate for you (maybe delete the entire string, or display 0.0 as value).
There is also another method:
- (BOOL) isPartialStringValid : (NSString*) partialString: (NSString*) partialString
errorDescription: (NSString*) error;
This way you can know if a partial string is valid.For example with the scientific notation "1e" is not valid, but is partially valid because the user may add 1 and it will become "1e1".
Create an NSNumberFormatter subclass and put this in the implementation. In your code, set the YKKNumberFormatter as the formatter for the NSTextField/UITextField.
#implementation YKKNumberFormatter
- (BOOL)isPartialStringValid:(NSString *)partialString newEditingString:(NSString **)newString errorDescription:(NSString **)error {
// Make sure we clear newString and error to ensure old values aren't being used
if (newString) { *newString = nil;}
if (error) {*error = nil;}
static NSCharacterSet *nonDecimalCharacters = nil;
if (nonDecimalCharacters == nil) {
nonDecimalCharacters = [[[NSCharacterSet decimalDigitCharacterSet] invertedSet] retain];
}
if ([partialString length] == 0) {
return YES; // The empty string is okay (the user might just be deleting everything and starting over)
} else if ([partialString rangeOfCharacterFromSet:nonDecimalCharacters].location != NSNotFound) {
return NO; // Non-decimal characters aren't cool!
}
return YES;
}
#end
I have set up my simple Xcode project with a table that is binded to an array controller. It works fine if the array controller is full of entities with a string attribute. However I want to change the attribute to a BOOL and have the table show the string "true" or "false" based on the BOOL.
I have overrided the following two methods from NSFormatter:
-(NSString*) stringForObjectValue:(id)object {
//what is the object?
NSLog(#"object is: %#", object);
if(![object isKindOfClass: [ NSString class ] ] ) {
return nil;
}
//i'm tired....just output hello in the table!!
NSString *returnStr = [[NSString alloc] initWithFormat:#"hello"];
return returnStr;
}
-(BOOL)getObjectValue: (id*)object forString:string errorDescription:(NSString**)error {
if( object ) {
return YES;
}
return NO;
}
So the table gets populated with "hello" if the attribute is a string however if I switch it to a boolean, then the table gets populated with lots of blank spaces.
I don't know if this helps but on the line where I'm outputting the object, it outputs __NSCFString if the attribute is a string and "Text Cell" if I switch the attribute to a boolean. This is something else I don't understand.
Ok, it's not 100% clear what you're trying to do from the code, but first things first - BOOL is not an object, it's basically 0 or 1, so to place BOOL values into an array, you're probably best off using NSNumber:
NSNumber *boolValue = [NSNumber numberWithBool:YES];
and placing these into your array. Now you want to change your method:
-(NSString*) stringForObjectValue:(id)object {
NSNumber *number = (NSNumber *)object;
if ([number boolValue] == YES)
return #"true";
else
return #"false";
}
There's a few things here - for example, you want to avoid passing around id references if you can (if you know all your objects in the NSArray are NSNumber, you shouldn't need to).
I need to check if an dict has a key or not. How?
objectForKey will return nil if a key doesn't exist.
if ([[dictionary allKeys] containsObject:key]) {
// contains key
}
or
if ([dictionary objectForKey:key]) {
// contains object
}
More recent versions of Objective-C and Clang have a modern syntax for this:
if (myDictionary[myKey]) {
}
You do not have to check for equality with nil, because only non-nil Objective-C objects can be stored in dictionaries(or arrays). And all Objective-C objects are truthy values. Even #NO, #0, and [NSNull null] evaluate as true.
Edit: Swift is now a thing.
For Swift you would try something like the following
if let value = myDictionary[myKey] {
}
This syntax will only execute the if block if myKey is in the dict and if it is then the value is stored in the value variable. Note that this works for even falsey values like 0.
if ([mydict objectForKey:#"mykey"]) {
// key exists.
}
else
{
// ...
}
When using JSON dictionaries:
#define isNull(value) value == nil || [value isKindOfClass:[NSNull class]]
if( isNull( dict[#"my_key"] ) )
{
// do stuff
}
I like Fernandes' answer even though you ask for the obj twice.
This should also do (more or less the same as Martin's A).
id obj;
if ((obj=[dict objectForKey:#"blah"])) {
// use obj
} else {
// Do something else like creating the obj and add the kv pair to the dict
}
Martin's and this answer both work on iPad2 iOS 5.0.1 9A405
One very nasty gotcha which just wasted a bit of my time debugging - you may find yourself prompted by auto-complete to try using doesContain which seems to work.
Except, doesContain uses an id comparison instead of the hash comparison used by objectForKey so if you have a dictionary with string keys it will return NO to a doesContain.
NSMutableDictionary* keysByName = [[NSMutableDictionary alloc] init];
keysByName[#"fred"] = #1;
NSString* test = #"fred";
if ([keysByName objectForKey:test] != nil)
NSLog(#"\nit works for key lookups"); // OK
else
NSLog(#"\nsod it");
if (keysByName[test] != nil)
NSLog(#"\nit works for key lookups using indexed syntax"); // OK
else
NSLog(#"\nsod it");
if ([keysByName doesContain:#"fred"])
NSLog(#"\n doesContain works literally");
else
NSLog(#"\nsod it"); // this one fails because of id comparison used by doesContain
Using Swift, it would be:
if myDic[KEY] != nil {
// key exists
}
Yes. This kind of errors are very common and lead to app crash. So I use to add NSDictionary in each project as below:
//.h file code :
#interface NSDictionary (AppDictionary)
- (id)objectForKeyNotNull : (id)key;
#end
//.m file code is as below
#import "NSDictionary+WKDictionary.h"
#implementation NSDictionary (WKDictionary)
- (id)objectForKeyNotNull:(id)key {
id object = [self objectForKey:key];
if (object == [NSNull null])
return nil;
return object;
}
#end
In code you can use as below:
NSStrting *testString = [dict objectForKeyNotNull:#"blah"];
For checking existence of key in NSDictionary:
if([dictionary objectForKey:#"Replace your key here"] != nil)
NSLog(#"Key Exists");
else
NSLog(#"Key not Exists");
Because nil cannot be stored in Foundation data structures NSNull is sometimes to represent a nil. Because NSNull is a singleton object you can check to see if NSNull is the value stored in dictionary by using direct pointer comparison:
if ((NSNull *)[user objectForKey:#"myKey"] == [NSNull null]) { }
Solution for swift 4.2
So, if you just want to answer the question whether the dictionary contains the key, ask:
let keyExists = dict[key] != nil
If you want the value and you know the dictionary contains the key, say:
let val = dict[key]!
But if, as usually happens, you don't know it contains the key - you want to fetch it and use it, but only if it exists - then use something like if let:
if let val = dict[key] {
// now val is not nil and the Optional has been unwrapped, so use it
}
I'd suggest you store the result of the lookup in a temp variable, test if the temp variable is nil and then use it. That way you don't look the same object up twice:
id obj = [dict objectForKey:#"blah"];
if (obj) {
// use obj
} else {
// Do something else
}
if ([MyDictionary objectForKey:MyKey]) {
// "Key Exist"
}
As Adirael suggested objectForKey to check key existance but When you call objectForKeyin nullable dictionary, app gets crashed so I fixed this from following way.
- (instancetype)initWithDictionary:(NSDictionary*)dictionary {
id object = dictionary;
if (dictionary && (object != [NSNull null])) {
self.name = [dictionary objectForKey:#"name"];
self.age = [dictionary objectForKey:#"age"];
}
return self;
}
if ( [dictionary[#"data"][#"action"] isKindOfClass:NSNull.class ] ){
//do something if doesn't exist
}
This is for nested dictionary structure