Tuesday, December 31, 2013

UI_USER_INTERFACE_IDIOM

if (UIUserInterfaceIdiomPad == UI_USER_INTERFACE_IDIOM()) {
    NSLog(@"pad");
} else {
    NSLog(@"phone");
}

Monday, December 16, 2013

UIKit Version Numbers detektalasa futasi idoben


Cedric Luthi kommentje Steinberger Peter snippetje alatt pontosan leirja:

In order to check which SDK version was used to build a binary, UIKit uses the _UIApplicationLinkedOnOrAfterfunction. It is implemented by comparing the major version of UIKit at link time (NSVersionOfLinkTimeLibrary("UIKit") >> 16) to a value in the __UIKitVersionNumbers table.

Here is this UIKit version numbers table, built by running otool -L on UIKit of all these iOS versions (yes I have a huge archive!):

2.00 x0E5
2.1 0x2EB
2.2 0x2F0
2.2.1 0x2F1
3.0 0x333
3.1 0x3E8
3.2 0x44C
4.0 0x4B0
4.1 0x514
4.2.1 0x578
4.2.6 0x582
4.3 0x5DC
5.0 0x640
5.1 0x6A4
6.0 0x944
6.1 0x94C
7.0 0xB57
7.1 0xB77
Weirdly enough, the __UIKitVersionNumbers contains 0x2EC instead of 0x2EB for iPhone OS 2.1. But since nobody cares at all about iPhone OS 2 this should not be a problem.

Peter is igy allapitja meg, hogy a 7-estol hasznalt flat design-hoz igazodjon vagy meg a regihez:
#define UIKitVersionNumber_iOS_7_0 0xB57
BOOL PSPDFIsUIKitFlatMode(void) {
    static BOOL isUIKitFlatMode = NO;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        // We get the modern UIKit if system is running >= iOS 7 and we were linked with >= SDK 7.
        if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_7_0) {
            isUIKitFlatMode = (NSVersionOfLinkTimeLibrary("UIKit") >> 16) >= UIKitVersionNumber_iOS_7_0;
        }
    });
    return isUIKitFlatMode;
}

Thursday, December 12, 2013

KVC Collection Operators

Itt olvahato a teljes NSHipster iras.

Simple Collection Operators:

  • @count: Returns the number of objects in the collection as an NSNumber.
  • @sum: Converts each object in the collection to a double, computes the sum, and returns the sum as an NSNumber.
  • @avg: Takes the double value of each object in the collection, and returns the average value as an NSNumber.
  • @max: Determines the maximum value using compare:. Objects must support comparison with one another for this to work.
  • @min: Same as @max, but returns the minimum value in the collection.

[products valueForKeyPath:@"@count"]; // 4[products valueForKeyPath:@"@sum.price"]; // 3526.00[products valueForKeyPath:@"@avg.price"]; // 881.50[products valueForKeyPath:@"@max.price"]; // 1699.00[products valueForKeyPath:@"@min.launchedOn"]; // June 11, 2012

Object Operators:
  • @unionOfObjects / @distinctUnionOfObjects: Returns an array of the objects in the property specified in the key path to the right of the operator.
    @distinctUnionOfObjects removes duplicates, whereas @unionOfObjects does not.
Array and Set Operators:
  • @distinctUnionOfArrays / @unionOfArrays: Returns an array containing the combined values of each array in the collection, as specified by the key path to the right of the operator. As you'd expect, the distinct version removes duplicate values.
  • @distinctUnionOfSets: Similar to @distinctUnionOfArrays, but it expects an NSSet containing NSSet objects, and returns an NSSet. Because sets can't contain duplicate values anyway, there is only the distinct operator.

Tuesday, December 3, 2013

Frame vs Bounds

csak emlekeztetonek:
Ash Furrow: "A view's frame is the position and size with respect to its parent's coordinate system. A view's bounds is the position and size with respect to its own coordinate system."

Monday, December 2, 2013

Automatikusan sythesized property accessor-ok

Ha egy class-nak van egy property-je amihez legalabb egy accessor method-ot eloallit a compiler (azaz nem irtunk sajat gettert vagy settert vagy readonly-nal getter-t), akkor magat a propertyt is automatikusan eloallitja (nem kell @synthesize az implementacioban). Ha viszont sajat gettert es settert irunk (vagy readonly-nal gettert) akkor nem lesz maga a property sem automatikusan eloallitva azaz kella a: @synthesize property = _property;

Designated Initializer Pattern

Ha tobb init method is van egy Class-on akkor azt hivjuk Designated Intializer-nek amelyik valoban beallitja az instancia valtozokat (es meghivja a superclass init-jet). A tobbi init pedig ezt hivja.
pl.:
- (id)initWithFirstName:(NSString *)aFirstName lastName:(NSString *)aLastName dateOfBirth:(NSDate *)aDOB {
    //set properties
}

- (id)initWithFirstName:(NSString *)aFirstName lastName:(NSString *)aLastName {
    return [self initWithFirstName:aFirstName lastName:aLastName dateOfBirth:nil];
}

- (id)init {
    return [self initWithFirstName:@"John" lastName:@"Doe" dateOfBirth:nil];
}

Sunday, December 1, 2013

Categoy, Class Extension, Method Swizzling

Letezo Class-t 2 felekeppen lehet kiboviteni oroklodes nelkul:
1. Categories (amivel egy letezo Class-hoz lehet method-okat adni):
@interface ClassName (CategoryName)
..
@end
pl:
hederbe (XYPerson+XYPersonExtraMethods.h):
#import “XYPerson.h”
@interface XYPerson (XYPersonExtraMethods) 
- (NSString *)lastNameFirstNameString;
@end
implementacio (XYPerson+XYPersonExtraMethods.m):
#import “XYPerson+XYPersonExtraMethods.m;
@implementation XYPerson (XYPersonExtraMethods)
- (NSString *)lastNameFirstNameString {
    return [NSString stringWithFormat:@”%@, %@”, self.lastName, self.fistName];
}
@end
Es utana igy lehet meghivni:
#import “XYPerson+XYPersonExtraMethods.h”;
@implementation someObject
- (void)someMethod {
    XYPerson *person = [[XYPerson alloc] initWithDefaultValues];
    NSLog(@”%@”, [person lastNameFirstNameString]);
}
@end
Vigyazni kell, mert ha 2 kulonbozo helyen is definialva van Category ugyanarra a Class-ra es elofordul ugyanolyan method mindket Category-ban, akkor undefinded, hogy futasi idoben melyik hivodik meg. Felul is lehet irni az eredti Class method-jat, de ha az eredetileg is egy Category-ban volt definialva akkor megint csak undefined, hogy melyik hivodik meg. Erre megoldas a Method Swizzling.

2. Class Extension (amivel egy Class internal impelmentaciojat lehet kiboviteni):
Hasonlit a Category-ra, de csak olyan Class-on lehet alkalmazni aminek megvan a soruce kodja (egy compile soran forditodik le mindketto es az eredeti Class implementaciojaba kell beleirni).
Anonymous Category-nak is hivjak es igy nez ki:
@interface ClassName () {
    id _someCustomInstanceVariable; //igy lehet instance valtozot hozzaadni
}
    @property NSObject *extraProperty; //A Category-val szemben itt property-ket is lehet definialni
@end
Sokszor private property-k es method-ok letrehozasara hasznaljak: readonly-nak adunk meg valamit az interface-n es readwrite-nak Class Extension-ban. 
XYPerson.h:
@interface XYPerson: NSObject
@property (readonly) NSString *anyProp;
- (void)assignAnyProp;
@end
XYPerson.m:
@interface XYPerson ()
@property (readwrite) NSString *anyProp; //readwrite elhagyhato, mert az a default
@end

@implementation XYPerson
@end
A compiler letrehoz egy settert igy most anyProperty csak belulrol allithato.
-----------------------
Egy letezo Class letezo Method-janak lecserelese. Ugyan Category-val is lehet override-olni meglevo Method-ot, de ha eredetileg is egy Category-ban volt a method akkor undefined, hogy melyik valtozat fut le, raadasul Mehod Swizzling-gel az eredeti method-ot is meg lehet hivni. A megoldas, hogy az uj method-ot mashogy nevezzuk el, majd kicsereljuk oket:
@implementation NSView (MyOverride)
- (void) override_drawRect: (NSRect)r {
    [self override_drawrect: r]; //itt valojaban mar a kicserelt eredeti drawRect-et hivjuk
    //whatever we want to add to the original method
}
@end
Igy csereljuk meg az uj method-ot az eredetivel:
void MehtodSwizzle(Class c, SEL origSEL, SEL overrideSEL) {
    Method origMethod = class_getInstanceMethod(c, origSEL);
    Method overrideMethod = class_getInstanceMethod( c, overrideSEL);
    //ha a method az eredeti Class superclass-aban letezik azt kulon kell kezelni mivel a class_getInstanceMethod ott is keres. Mivel a class_addMethod nem erinti a superclass-t ezert azzal lehet kiszurni hogy hol volt az origSEL eredetileg
    if (class_addMethod(c, origSEL, 
                        method_getImplementation(overrideMethod), 
                        method_getTypEncoding(overrideMethod))) {
    //ha az addMethod sikerult akkor az origSEL az origClass superclass-aban volt, de most mar ott van az origClass-ban az overrideMethod implementeaciojaval, mar csak az overrideSEL-t kell hozzaadni az origClass superclassaban levo origSEL implementaciojaval
        class_replaceMethod(c, overrideSEL, 
                            method_getImplementation(orgiMethod), 
                            method_getTypeEncoding(origMethod));
    }
    else {
    //ha az addMethod failed akkor az origClass-ban volt definialva az origMethod nem pedig a superclass-aban es ilyenkor siman meg lehet cserelni helyben a 2 method-ot
        method_exchangeImplementation(origMethod, overrideMethod);
    }
}
Vegul meg biztosnak kell lenni, hogy a MeghodSwizzle meghivodik a progam indulasanal es ezt elintezhetjuk a Category-ban:
+ (void)load {
   MethodSwizzle(self, @selector(drawRect:), 
                       @selector(override_drawRect));
}