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));
}

Thursday, September 26, 2013

encode URL

Igy tudunk URL encode-olni egy string-et:

NSString *fullPath = [NSString stringWithFormat:@"www.example.com/find?query=%@", query];
fullPath = [fullPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

de ezzel az a baj, hogy a query-ben levo URL karaktereket nem encode-olja. Erre itt van Simon javalata:

NSString * encodedString = (NSString *)CFURLCreateStringByAddingPercentEscapes(
     NULL,
     (CFStringRef)query,
     NULL,
     (CFStringRef)@"!*'();:@&=+$,/?%#[]",
     kCFStringEncodingUTF8 );

utana ezt az encodedString-et hasznalhatjuk a fullPath osszeallitasanal es akkor mar nem is kell a stringByAddingPercentEscapesUsingEncoding-ot meghivni.

Ha ugyanezt ARC-cal akarjuk hasznalni akkor pedig:
NSString *encodedQuery = (__bridge_transfer NSString*)CFURLCreateStringByAddingPercentEscapes(
     NULL,
     (CFStringRef)query,
     NULL,
     (CFStringRef)@"!*'();:@&=+$,/?%#[]",
     kCFStringEncodingUTF8 ); 

Ez viszont nem oldja meg a query-ben elfordulo " encode-olasat.

Wednesday, September 11, 2013

UIPickerView magassaga

Csak erre a harom ertekre lehet beallitani:
162.0, 180.0, 216.0

Tuesday, September 10, 2013

NSInteger to NSString

[@(myInt) stringValue];

Tuesday, June 4, 2013

Protected, Private, Static variables

Ryan Jones: Creating Protected and Private Variables in Objective-C Classes

Protected and Private without the @synthesize

There is an easy way to create protected and private variables for a class. This method does not utilize the @synthesize directive that is part of Xcode. So memory management is completely up to you. I find this method works very well with variables that are not descendants of NSObject because there is no memory management needed.

The interface file (class.h) and inside the @interface declaration, add a @protected or @private. Anything that follows the line will be protected or private respectively. The key is not to add the @property line with the description for the variable, nor the @synthesize in the implementation file (class.m).

@interface PhotoViewer : UIView {
  NSArray *images; // protected by default
  
  @protected
  int index; // protected in class
  
  @private
  UIImageView *imageView; // will be private in class
  UIView *customView; // will be private in class
}

@end

Subclasses of this sample PhotoViewer class will be able to see the index variable, however they will not be able to see the imageView nor the customView. Additionally, because there is no @synthesize at play here, retaining variables by the class will have to be done manually. So setting the imageView would look something like

@implementation
- (id)initWithFrame:(CGRect)frame {
  self = [super initWithFrame:frame];
  if (self) {
    imageView = [[UIImageView alloc] init]; // retain count of 1
  }
  return self;
}

- (void)dealloc {
  [imageView release];
  [super dealloc];
}
@end

No need to go over memory management in any further depth, suffice it to say, the imageView in the example above has been allocd so it must be released in the dealloc otherwise the class will run into memory issues and not get released.

Everyone Needs to Know

Static variables. Thinking you can shorthand this and create variables directly in the implementation file would be correct. It works. However, creating variables in the implementation block will create a static variable. Static variables, are of course, shared with every instance of the class. So using the example class above, if we created index in the @implementation part of the file, every time a PhotoViewer was created and set the index = 0;, every instance would have an index equal to 0.

This can be really useful for many things, especially games where an enemy ship may need to know how many other ships there are. So if we used the class above and created a static variable, it would look like

@implementation

int numberOfPhotoViewers = 0; // static variable for PhotoViewer count

- (id)initWithFrame:(CGRect)frame {
  self = [super initWithFrame:frame];
  if (self) {
    imageView = [[UIImageView alloc] init];
    numberOfPhotoViewers++;
  }
  return self;
}

- (void)dealloc {
  [imageView release];
  [super dealloc];
}
@end

[UIView endEditing:force]

Ha nem tudjuk melyik view-n kene meghivni a resignFirstResponder-t akkor:
[view endEditing:YES];
Peldaul ha van tobb UITextField es egy UIButton aminek a touchUpInside-jarara el akarjuk ereszteni az eppen szerkesztett UITextField-et.

Monday, June 3, 2013

The LLDB Debugger

Itt van egy tutorial. Amit pedig kerestem az a bt (gdb-ben meg backtrace is mukodott, de lldb-ben mar csak a bt).

Friday, May 31, 2013

Matt Galloway: Singletons in Objective-C

Innen:

Background

Singleton classes are an important concept to understand because they exhibit an extremely useful design pattern. This idea is used throughout the iPhone SDK, for example, UIApplication has a method called sharedApplication which when called from anywhere will return the UIApplication instance which relates to the currently running application.

How to implement

You can implement a singleton class in Objective-C using the following code:

MyManager.h
1
2
3
4
5
6
7
8
9
10
11
#import 

@interface MyManager : NSObject {
    NSString *someProperty;
}

@property (nonatomic, retain) NSString *someProperty;

+ (id)sharedManager;

@end
MyManager.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#import "MyManager.h"

@implementation MyManager

@synthesize someProperty;

#pragma mark Singleton Methods

+ (id)sharedManager {
    static MyManager *sharedMyManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedMyManager = [[self alloc] init];
    });
    return sharedMyManager;
}

- (id)init {
  if (self = [super init]) {
      someProperty = [[NSString alloc] initWithString:@"Default Property Value"];
  }
  return self;
}

- (void)dealloc {
  // Should never be called, but just here for clarity really.
}

@end

What this does is it defines a static variable (but only global to this translation unit)) called sharedMyManager which is then initialised once and only once in sharedManager. The way we ensure that it’s only created once is by using the dispatch_once method from Grand Central Dispatch (GCD). This is thread safe and handled entirely by the OS for you so that you don’t have to worry about it at all.

However, if you would rather not use GCD then you should use the following code for sharedManager:

Non-GCD based code
1
2
3
4
5
6
7
+ (id)sharedManager {
    @synchronized(self) {
        if (sharedMyManager == nil)
            sharedMyManager = [[self alloc] init];
    }
    return sharedMyManager;
}

Then you can reference the singleton from anywhere by calling the following function:
MyManager *sharedManager = [MyManager sharedManager];

I’ve used this extensively throughout my code for things such as creating a singleton to handle CoreLocation or CoreData functions.