Saturday, March 22, 2014

UIImage: loading, decompressing

Here is a very nice article:
Avoiding Image Decompression Sickness
I liked the part explaining the memory usage for an image:
Looking at memory used an image takes multiple chunks of it:
1. space on disk or being transferred over the internet
2. uncompressed space, typically width*height*4 Bytes (RGBA)
3. when displayed in a view the view itself also needs space for the layer backing store

The function presented in this article loads an image:

This function decompress the image:

Saturday, March 8, 2014

Objective-C: Array Sorting

The following program shows how to sort an array of people with descriptors and using comparator:
Console:
2014-03-08 19:10:28.489 Sorting[84868:303] unsorted: (
    "Einshtein Albert",
    "Napoleon Bonapart",
    "Kutozov Michail",
    "Zhukov Georgiy",
    "Nabokov Vladimir",
    "Nikulin Yuri",
    "Nietzsche Friedrich"
)
2014-03-08 19:10:28.491 Sorting[84868:303] sortedArrayUsingDescriptors: (
    "Einshtein Albert",
    "Kutozov Michail",
    "Nabokov Vladimir",
    "Napoleon Bonapart",
    "Nietzsche Friedrich",
    "Nikulin Yuri",
    "Zhukov Georgiy"
)
2014-03-08 19:10:28.491 Sorting[84868:303] sortedArrayUsingComparator: (
    "Einshtein Albert",
    "Kutozov Michail",
    "Nabokov Vladimir",
    "Napoleon Bonapart",
    "Nietzsche Friedrich",
    "Nikulin Yuri",
    "Zhukov Georgiy"
)

Program ended with exit code: 0

Saturday, December 21, 2013

Cool NSExpression

Just for fun:
#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        
        NSExpression *expression = [NSExpression expressionWithFormat:@"(2 + 2) * 2"];
        id value = [expression expressionValueWithObject:nil context:nil];
        
        NSLog(@"4 + 5 - 2**3 == %f", [value floatValue]);
    }
    return 0;

}

Console:
2013-12-21 19:36:38.404 Expression[56749:303] (2 + 2) * 2 == 8.000000

Or a bit more complicated:
#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        
        NSExpression *expression = [NSExpression expressionWithFormat:@"2 + 2 ** 3"];
        id value = [expression expressionValueWithObject:nil context:nil];
        
        NSLog(@"2 + 2 ** 3 == %f", [value floatValue]);
    }
    return 0;

}

Console:
2013-12-21 19:37:18.340 Expression[56763:303] 2 + 2 ** 3 == 10.000000

Or even evaluate a formula:
#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{

    @autoreleasepool {
     
        NSExpression *expression = [NSExpression expressionWithFormat:@"2 * x + 4 * y"];
        id value = [expression expressionValueWithObject:@{ @"x": @2, @"y" : @4} context:nil];
        NSLog(@"result = %f", [value floatValue]);
    }
    return 0;

}

Console:
2013-12-21 19:55:32.572 Expression[56795:303] result = 20.000000

Calculate an average of numbers:
#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{

    @autoreleasepool {
     
        NSArray *arrNumbers = @[@3, @6, @3, @8, @4, @12, @9, @11];
        
        NSExpression *expression = [NSExpression expressionForFunction:@"average:" arguments:@[[NSExpression expressionForConstantValue:arrNumbers]]];
        id value = [expression expressionValueWithObject:nil context:nil];
        
        NSLog(@"average of numbers 3, 6, 3, 8, 4, 12, 9, 11 is %f", [value floatValue]);
    }
    return 0;

}
Console:
2013-12-21 19:51:15.771 Expression[56781:303] average of numbers 3, 6, 3, 8, 4, 12, 9, 11 is 7.000000

Let's calculate a deviation of numbers:
#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{

    @autoreleasepool {
     
        NSArray *arrNumbers = @[@3, @6, @3, @8, @4, @12, @9, @11];
        NSExpression *expression = [NSExpression expressionForFunction:@"stddev:" arguments:@[[NSExpression expressionForConstantValue:arrNumbers]]];
        id value = [expression expressionValueWithObject:nil context:nil];
        NSLog(@"deviation of numbers 3, 6, 3, 8, 4, 12, 9, 11 is %f", [value floatValue]);
    }
    return 0;

}

Console:
2013-12-21 19:46:14.628 Expression[56772:303] deviation of numbers 3, 6, 3, 8, 4, 12, 9, 11 is 3.316625

Thursday, December 19, 2013

Objective-C: Serialize to JSON

Since iOS 5 serialization to JSON is pretty simple:

This sample above, where a dictionary (attributes) is saved in an ASCII file, demonstrates all major rules:
1. An dictionary (or an array) can be converted to a JSON object.
2. This array or dictionary may contain NSString, NSNumber, NSValue, NSArray or NSDictionary objects.

It's even simpler to deserialize such JSON file. For example, this Mac OS command line app will read and parse the json-file created in the previous app:

File "json_file.json" should be in the same folder where the executable is. For an iOS application this json-file can be added to the project and read from the app bundle:
NSString *fileName = [[NSBundle mainBundle] pathForResource:@"json_file" ofType:@"json"];

Saturday, November 30, 2013

Check if a file exists on the web

This method does work. Is it faster than simply download the file? If it is a huge file and it does exist, the downloading will take a long time. I'd like to hope that this method works faster. But it does not give a response immediately, so better to wrap it in a queue.

Tuesday, September 3, 2013

Objective-C: Swizzling

Swizzling is a voodoo technique in Objective-C allowing to change implementations of an existing selector.
In Objective-C the class maintain a dispatch table that is used to resolve the messages sent in runtime. Each entry in this table is a method with a particular name (selector) to an implementation, which points to an underlying C function. To swizzle a method is to change a class's dispatch table in order to resolve messages from an existing selector to a different implementation, while aliasing the original method implementation to a new selector.
Here is the simplest example of the method swizzling:

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

int main(int argc, const char * argv[])
{

    @autoreleasepool {

        Method one = class_getInstanceMethod([NSString class], @selector(lowercaseString));
        Method two = class_getInstanceMethod([NSString class], @selector(uppercaseString));
        
        NSString *text = @"hElO, wOrLd!";
        NSLog(@"Normal: %@", [text lowercaseString]);
        
        method_exchangeImplementations(one, two);
        NSLog(@"Swizzled: %@", [text lowercaseString]);
        
    }
    return 0;
}


Output:

2013-09-03 17:00:45.254 Swizzle[50579:303] Normal: helo, world!
2013-09-03 17:00:45.256 Swizzle[50579:303] Swizzled: HELO, WORLD!

Same method lowercaseString from NSString class is called, but it gives different results.

A bit more useful example with the same method but with a logging added:
#import <Foundation/Foundation.h>
#import <objc/runtime.h>

@interface NSString (Swizzling)

- (NSString *)myLowercaseString;

@end

@implementation NSString (Swizzling)

- (NSString *)myLowercaseString
{
    NSLog(@"Entering %s", __FUNCTION__);
    return [self myLowercaseString]; // This is not a mistake. The implementations are swept.
}

@end

int main(int argc, const char * argv[])
{
    
    @autoreleasepool {
        
        Method one = class_getInstanceMethod([NSString class], @selector(lowercaseString));
        Method two = class_getInstanceMethod([NSString class], @selector(myLowercaseString));
        method_exchangeImplementations(one, two);
        
        NSString *text = @"hElO, wOrLd!";
        NSLog(@"Swizzled: %@", [text lowercaseString]);
        
    }
    return 0;
}
Output:

2013-09-03 17:08:59.601 Swizzle[50593:303] Entering -[NSString(Swizzling) myLowercaseString]
2013-09-03 17:08:59.604 Swizzle[50593:303] Swizzled: helo, world!

Saturday, August 24, 2013

Objective-C: Comparing Objects.

Well-known facts in the beginning: operator == compares only pointers values - it shows that two pointers point to the same object. Method isEqual: from the NSObject protocol is used when we need to know that two objects contain the same data. Moreover, some classes may have own comparing methods. For example, class NSString has isEqualToString: method. The following example illustrates all that said above:

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        NSString *text1 = @"String number 1.";
        NSString *text2 = [NSString stringWithFormat:@"String number %i.", 1];
        
        BOOL equal1 = (text1 == text2);
        NSLog(@"pointer values are %@", equal1 ? @"equal" : @"not equal");
        
        BOOL equal2 = [text1 isEqual:text2];
        NSLog(@"objects are %@", equal2 ? @"equal" : @"not equal");

        BOOL equal3 = [text1 isEqual:text2];
        NSLog(@"string objects are %@", equal3 ? @"equal" : @"not equal");
    }
    return 0;
}


The output in the console looks so:

2013-08-24 14:11:46.140 CompareStrings[75203:303] pointer values are not equal
2013-08-24 14:11:46.142 CompareStrings[75203:303] objects are equal
2013-08-24 14:11:46.142 CompareStrings[75203:303] string objects are equal

Everything's clear: text1 and text2 are two different objects of NSString class. So the variable equal1 is NO. But the text in these two object is the same, so variables equal2 and equal3 is YES.
One small question about this code: why I need isEqualToString: method in NSString, if I already have isEqual:? The answer is obvious: probably, isEqualToString: method is optimised for using with NSString objects. What will be if I pass an object of another class to this method? Probably, I'll get a warning:

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        
        NSString *text = @"http://www.google.com";
        NSURL *url = [NSURL URLWithString:@"http://www.google.com"];
        
        BOOL equal = [text isEqualToString:url];
        NSLog(@"objects are %@", equal ? @"equal" : @"not equal");
    }
    return 0;
}

Xcode shows the warning:
"Incompatible pointer types sending "NSURL *" to parameter of type "NSString *".
In the console:

2013-08-24 14:25:40.815 CompareStrings[75226:303] objects are not equal

It's a minimal information about the object comparing in Objective-C that everybody knows. As expected, class NSArray has method isEqualToArray:

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        NSArray *array1 = @[ @1, @3, @5 ];
        NSArray *array2 = @[ @1, @3, @5 ];
        NSArray *array3 = @[ @1, @3, @4 ];
        BOOL equal = [array1 isEqualToArray:array2];
        NSLog(@"array1 and array2 are %@", equal ? @"equal" : @"not equal");
        
        equal = [array1 isEqualToArray:array3];
        NSLog(@"array1 and array3 are %@", equal ? @"equal" : @"not equal");
    }
    return 0;
}
The output:
2013-08-24 14:37:05.889 CompareArrays[75273:303] array1 and array2 are equal
2013-08-24 14:37:05.891 CompareArrays[75273:303] array1 and array3 are not equal

NSDictionary has method isEqualToDictionary: and so on.

One more thing...
iOS Reference Library: Concepts in Objective-C programming: Object Comparison.
This is just one page of text:

  • it explains what the default method isEqual: is - it compares the pointers only;
  • it explains how to override this isEqual: method in subclasses - check the pointer equality, then check the class equality and finally check necessary properties;
  • a method hash is mentioned - it generates an integer value that is used as the object table address in the object collections;
  • if two objects are equal, they must have the same hash value.

Here is how I understand it. Seems like the default implementation of isEqual: looks so:

- (BOOL)isEqual:(id)object
{
    return self == object;
}

An overridden version of this method may look so:

@interface Person : NSObject

@property (copy) NSString *firstName;
@property (copy) NSString *lastName;

@end

@implementation Person

- (BOOL)isEqual:(id)object
{
    if ( self == object ) {
        return YES;
    }
    
    if ( ![object isKindOfClass:[Person class]] ) {
        return NO;
    }
    
    if ( ![_firstName isEqualToString:[object firstName]] ) {
        return  NO;
    }

    if ( ![_lastName isEqualToString:[object lastName]] ) {
        return  NO;
    }
    
    return YES;
}

@end

Each class has method hash, probably, implemented so:
- (NSUInteger)hash
{
    return (NSUInteger)self;
}

This method is used when class objects are added to a collection like NSDictionary, this method determines the object address in this collection. So it's clear , that this method should return the same value for the equal objects. 
In the Person class mentioned above method hash may look like:
- (NSUInteger)hash
{
    return [[NSString stringWithFormat:@"%@ %@", _firstName, _lastName] hash];
}

Now, two Person objects with the same firstName and lastName will have the same hash. Make sense to propose a bit faster implementation:
- (NSUInteger)hash
{
    NSUInteger hash1 = [_firstName hash];
    NSUInteger hash2 = [_lastName hash];
    return  hash1 ^ hash2;
}

You see that two different objects of class Person may have same hash. For example, "Alan Smith" and "Smith Alan". This problem has name hash collision.
If we will continue, we will have to talk about another problem - mutable pitfall - mutable objects are added to a collection and then changed.
So it looks like an endless question.

More inforamation:
1. iOS Reference Library: Concepts in Objective-C programming. Object Comparison
2. Friday Q&A 2010-06-18: Implementing Equality and Hashing
3. Obj-C Optimization: Optimized Hashing in Mac OS X