NSString Category Method Not Getting Called - ios

The problem I am trying to solve is to convert nil strings into empty strings so I can put that as a value in NSDictionary.
I have the following code:
//Accessed in class
prospect.title = [self.titleLabel.text emptyWhenNil];
// NSString+Additions Category
-(NSString *) emptyWhenNil
{
if(self == nil)
return #"";
return self;
}
But for some reason the emptyWhenNil method is never even invoked!! I am lost..

The problem is, when your string pointer is nil, you have no object to send that category message to. Messages to nil are not executed (and return nil) in Objective-C.
If you want to put "null" objects into a collection, such as an NSDictionary, or NSArray, you can use the NSNull class instead.
Alternatively you could implement this method as a class method:
+ (NSString *)emptyStringIfNil:(NSString *)str {
if (!str) return #"";
return str;
}
You would then call this as
prospect.title = [NSString emptyStringIfNil:self.titleLabel.text];

If the string is nil, there is no self to execute the method on. The default behaviour of the runtime in this situation is to return a default nil value.
You should implement this as a static method instead. Something like this:
+ (NSString *)emptyStringIfNil:(NSString *)input
{
return input ? input : #"";
}

If the NSString pointer is nil, the method will not be called on it, what you can do is create a static method:
+ (NSString *) emptyIfNil:(NSString *) str
{
return str == nil ? #"" : str;
}

Related

NSNull returns <null> instead of returning null

I'm using the following code to check if a NSNumber has nil value. So I'm converting the NSNumber to string and Im checking if its length is 0. If it is of zero, Im returning NSNull else Im returning the number itself.
- (id)NSNullToNilForKey:(NSNumber *)number
{
if ([[number stringValue] length] == 0){
return [NSNull null];
}
return number;
}
Im invoking it as follows,
NSString *bodyString = [NSString stringWithFormat:#"[ \"%#\",{\"session_token\": \"%#\",\"request\": [\"GetAssigneeWiseCompliancesChart\",{\"country_id\": %#,\"business_group_id\": %#,\"legal_entity_id\": %#,\"division_id\": %#,\"unit_id\": %#,\"user_id\": %#}]}]",clientSessionId,clientSessionId,[self NSNullToNilForKey:countryId],[self NSNullToNilForKey:businessGroupId],[self NSNullToNilForKey:legalEntityId],[self NSNullToNilForKey:divId],[self NSNullToNilForKey:unitId], [self NSNullToNilForKey:userId]];
But the problem is that, though the if loop is getting invoked. The value returned from the if loop of NSNullToNilForKey is <null> instead of null. How can I sort this out?
You're creating a string from a format, all of the parameters are added by taking their description, what you're seeing is the description of the NSNull instance.
Your method should specifically return a string and you should choose explicitly what string you want to return.
- (id)NSNullToNilForKey:(NSNumber *)number
{
if ([[number stringValue] length] == 0){
return #"NSNull";
}
return number;
}
try this
change the type anyobject id to NSNumber *
- (NSNumber *)NSNullToNilForKey:(NSNumber *)number
{
if ([[number stringValue] length] == 0){
return [NSNull null];
}
return number;
}

nil object in NSDictionary

I have a NSDictionary from which I read some values in two different methods in my code, however only in one of the methods the value of the key is retrieved correctly whereas in the other method I always get nil.
This is the method that works:
-(void)drawDriver:(NSString*)driverId withPosition:(CLLocationCoordinate2D)position withRotation:(float)bearing isAvailable:(BOOL)isDriverAvailable{
GMSMarker *driverMarker = [driversList objectForKey:driverId];
if (driverMarker != nil) {
// do some work
}
}
and it's called from this other method:
- (void) socketIO:(SocketIO *)socket didReceiveMessage:(SocketIOPacket *)packet
{
NSMutableDictionary *datos = (NSMutableDictionary*)packet.data;
NSDictionary *driverId = datos[#"from"];
NSString *id = [driverId objectForKey:#"id"];
//gets other values
NSLog(#"Socket message: driverId: %#, position %f,%f, isAvailable:%d", id, latitude, longitude, isDriverAvailable);
//Call the first method
[self drawDriver:id withPosition:position withRotation:bearing isAvailable:isDriverAvailable];
}
And this is the method that doesn't work (returns nil for driverMarker):
-(void)updateMapForTripWithDriver:(NSString *)driverId {
GMSMarker *driverMarker = [driversList objectForKey:driverId];
if (driverMarker != nil) {
//do some work
}
}
and this is called from here:
- (void)updateTripWithData:(NSDictionary *)data {
//This NSDictionary comes from a notification
NSString *newStatus = [[data objectForKey:#"aps"] objectForKey:#"alert"];
if ([newStatus isEqualToString:NO_TRIP]) {
} else if ([newStatus isEqualToString:WAITING_CONFIRMATION]) {
} else if ([newStatus isEqualToString:DRIVER_ON_THE_WAY]) {
//Get the driverId and call the other method
NSString *driverId = [data objectForKey:#"driver_id"];
[self updateMapForTripWithDriver:driverId];
}
}
As you can see both methods have the exact same code to retrieve the object but still I get different results.
The only difference I could find is when I put some breakpoints on the methods and this is what I found:
On the first method, although I pass the driverId as a NSString, somehow it's read as NSFCNumber and that seems to work because I get the value with no problems.
But on the second method the key is read as an actual NSString which for some reason makes the method to return nil for an object that does exists on the NSDictionary.
How can I get the second method to work and return the right value?

Objective C static class member having bad access

I am trying to use the static variable here tagsToCheck, accessible from all static methods in this class.
What is the best way?
A retain here solve the problem, but is it the right way?
tagsToCheck = [#[#"<html>", #"<br>", #"<br />", #"<br/>", #"<p>", #"<div>", #"<b>",
#"<i>", #"<font>", #"<ul>", #"<li>"] retain];
The original code is,
static NSArray * tagsToCheck = nil;
#implementation DictionaryUtil
+ (void) initialize {
tagsToCheck = #[#"<html>", #"<br>", #"<br />", #"<br/>", #"<p>", #"<div>", #"<b>",
#"<i>", #"<font>", #"<ul>", #"<li>"];
}
+ (BOOL) isHtml:(NSString *)string
{
if (!string) return NO;
for (NSString *tag in tagsToCheck) { // bad access here for tagsToCheck
if ([string rangeOfString:tag options:NSCaseInsensitiveSearch].location != NSNotFound) {
return YES;
}
}
return NO;
}
Yes the Objective-C array literal is an autoreleased object, so using retain is correct.
Using retain is not the best way. The best way is to enable Automatic Reference Counting.

iOS Incompatible pointer types returning NSDictionary from NSMutableDictionary

I'm having an issue where I use NSMutableDictionaries returns values from NSDictionary.
Here is the warning message:
incompatible pointer types returning 'NSDictionary *' from a function
with result type 'NSMutableDictionary *'
Here is the code:
- (NSMutableDictionary *)dictionaryWithContentsAtPath:(NSString *)path
{
if ([path rangeOfString:#"/SessionStore"].location == 0)
{
return [_inMemoryCache objectForKey:[path stringByReplacingCharactersInRange:NSMakeRange(0, 13) withString:#""]];
}
if ([path rangeOfString:#"/PermanentStore"].location == 0)
{
return [NSDictionary dictionaryWithContentsOfFile:[self.persistentStoragePath stringByAppendingPathComponent:[path substringFromIndex:15]]];
}
return nil;
}
Please help me how to resolve this warning.
You need to ensure you're returning the right type. Your method states it's returning an NSMutableDictionary, but then returns only an NSDictionary.
Try this instead:
- (NSMutableDictionary*)dictionaryWithContentsAtPath:(NSString*)path {
if ([path rangeOfString:#"/SessionStore"].location == 0) {
return [[_inMemoryCache objectForKey:[path stringByReplacingCharactersInRange:NSMakeRange(0, 13) withString:#""]] mutableCopy];
}
if ([path rangeOfString:#"/PermanentStore"].location == 0) {
return [NSMutableDictionary dictionaryWithContentsOfFile:[self.persistentStoragePath stringByAppendingPathComponent:[path substringFromIndex:15]]];
}
return nil;
}
Note: added a call to mutableCopy to turn your literal NSDictionary into a mutable version, and in the second case, used called the dictionaryWithContentsOfFile method on the NSMutableDictionary subclass instead of the NSDictionary parent class.

Core Data: Automatically Trim String Properties

For my Core Data NSManagedObject, I would like to ensure any NSString properties only contain strings that have been trimmed of whitespace.
I'm aware that I could achieve this by overriding each setter method, like so:
- (void)setSomeProperty:(NSString *)someProperty
{
someProperty = [someProperty stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ((!someProperty && !self.someProperty) || [someProperty isEqualToString:self.someProperty]) return;
[self willChangeValueForKey:#"someProperty"];
[self setPrimitiveValue:someProperty forKey:#"someProperty"];
[self didChangeValueForKey:#"someProperty"];
}
However, this seems like a lot of code to have to write, especially since my managed object is likely to have quite a few NSString properties.
Is there an easier way?
You could create a custom NSValueTransformer for NSString and assign all of your NSString properties to the new transformer in the model editor:
#interface StringTransformer: NSValueTransformer {}
#end
#implementation StringTransformer
+ (Class)transformedValueClass {
return [NSString class];
}
+ (BOOL)allowsReverseTransformation {
return YES;
}
- (id)transformedValue:(id)value {
return value;
}
- (id)reverseTransformedValue:(id)value {
return [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
#end
If you only need to ensure that the saved data is trimmed then you can implement willSave and use changedValues to check only the changed values. This will also make it easy to do in a loop to minimise code duplication.
You could do it during property validation:
- (BOOL)validateSomeProperty:(id *)inOutValue error:(NSError **)error
{
if (inOutValue)
{
NSString *value = *inOutValue;
*inOutValue = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
return YES;
}
Core data will automatically call validateSomeProperty:error: before saving your record, so this will make sure that any data that gets saved is trimmed. It won't stop the on-change events firing if someone changes it from, say, foo to \n\nfoo\n\n, but it does mean that you don't have to fire them by hand.

Resources