2014年6月7日 星期六

IOS Custom Page Control

How To Create UIPageViewController Using Storyboard

今天剛好在玩UIPageViewController,看到兩個不錯的功能
1. 只要實作以下兩個method,PageControll就會生出來
2. 但是 PageControll 被 UIPageViewController 藏得死死低,所以有另外一種方式把PageControll 做 Customize

To display a page indicator, you have to tell iOS the number of pages (i.e. dots) to display in the page view controller and which page must be selected at the beginning. Add the following two methods at the end of the ViewController.m file:

- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController
{
    return [self.pageTitles count];
}

- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController
{
    return 0;
}

Customize the Page Indicator

If you compile and run the app now, your app should run properly but you may find the page indicator missing. Actually the page indicator is there but the color of the dots is the same as the color of the view. So let’s change its color.
In the AppDelegate.m, add the following lines of code in the didFinishLaunchingWithOptions: method:

UIPageControl *pageControl = [UIPageControl appearance];
pageControl.pageIndicatorTintColor = [UIColor lightGrayColor];
pageControl.currentPageIndicatorTintColor = [UIColor blackColor];
pageControl.backgroundColor = [UIColor whiteColor];
How do I make the bottom bar with dots of a UIPageViewController translucent?

2014年6月5日 星期四

IOS Property,Instance variable 傻傻分不清楚

Programming with Objective-C --- Encapsulating Data --- You Can Implement Custom Accessor Methods



Note: The compiler will automatically synthesize an instance variable in all situations where it’s also synthesizing at least one accessor method. If you implement both a getter and a setter for a readwrite property, or a getter for a readonly property, the compiler will assume that you are taking control over the property implementation and won’t synthesize an instance variable automatically.



編譯器會自動合成你的property,如果你的R/W property 實作setter & getter,又或者你的R-Only property 實作了getter的話,編譯器會認為你已經做好property的控制,因此編譯器就不會幫你自動生成實體變數摟!!

如果你還是需要實體變數的話呢,你必須合成它
@synthesize property = _property;
難得找到OC的一些歷史,之前一直對Property和Instance variable分不清楚。
歷史:几个有用的Objective-C新特性

原來以前在宣告Property(name)的同時,還必須再宣告同名的Instance variable(_name),最後再使用synthesize把這兩者關聯在一起(@synthesize name = _name;)

現在只要宣告一行Property就全部搞定了

2014年6月3日 星期二

IOS Adopting Modern Objective-C(未完)

Adopting Modern Objective-C

Over the years, the Objective-C language has grown and evolved. Although the core concepts and practices remain the same, parts of the language have been through significant changes and improvements. These modernizations improve type safety, memory management, performance, and other aspects of Objective-C, making it easier for you to write correct code. It’s important to adopt these changes in your existing and future code to help it become more consistent, readable, and resilient.
多年來,Objective-C逐漸發展及演變。雖然核心概念和做法保持一致,部分的語言已經通過顯著的變化和改進。這些現代化(modernizations)改進了類型安全,記憶體管理,性能和Objective-C的其他方面,使您更輕鬆地編寫出正確的代碼。採用這些變化到你既有或未來的程式碼是非常重要的,讓它變得更加一致,可讀性,彈性。 


instancetype


Use the instancetype keyword as the return type of methods that return an instance of the class they are called on (or a subclass of that class). These methods include alloc, init, and class factory methods.

@interface MyObject

- (instancetype)myFactoryMethod;

@end

個人理解是allocinit, and class factory methods 都從回傳 id 改成回傳 instancetype


To make sure instancetype factory methods have the right subclassing behavior, be sure to use [self class] when allocating the class rather than referring directly to the class name.
為了確保instancetype工廠方法有正確的子類的行為,一定要使用[self class] when allocating the class rather than referring directly to the class name.
+ (instancetype)factoryMethodA { return [[[self class] alloc] init]; }


Properties

Using properties instead of instance variables in as many places as possible provides many benefits:
  • Autosynthesized getters and setters. When you declare a property, by default getter and setter methods are created for you.
  • Better declaration of intent of a set of methods. Because of accessor method naming conventions, it’s clear exactly what the getter and setter are doing.
  • Property keywords that express  information about behavior. Properties provide the potential for declaration of attributes like assign (vs copy), weakatomic (vs nonatomic), and so on.
使用property而不是實體變數,可以提供許多好處在許多方面
1. 自動合成getter & setter
2. 更明確的方法意圖:因為存取方法已有它的命名慣例,因此它可以很明確的說明getter & setter 在幹嘛 XD
3. property的關鍵字表達了額外的行為資訊:如copy,assign,weak等等

The naming convention for Boolean properties is to declare them with a named getter starting with the word “is”:
@property (readonly, getter=isBlue) BOOL blue;
As a result, all of the following work:
if (color.blue) { }
if (color.isBlue) { }
if ([color isBlue]) { }
When deciding what can be a property, keep in mind that the following are not properties:
  • init method
  • copy method, mutableCopy method
  • A class factory method
  • A method that initiates an action and returns a BOOL result
  • A method that explicitly changes internal state as a side effect of a getter
請注意下列幾項不是property
1. init 方法
2. copy, mutableCopy 方法
3. 類別工廠方法
4. 發起行動後並回傳BOOL結果的方法
5. 明確低改變內部狀態(副作用)的getter
Additionally, consider the following set of rules when identifying potential properties in your code:


  • A read/write property has two accessor methods. The setter takes one argument and returns nothing, and the getter takes no arguments and returns one value. If you convert this set of methods into a property, tag it with the readwrite keyword.
  • A read-only property has a single accessor method, the getter, which takes no arguments and returns one value. If you convert this method into a property, tag it with the readonly keyword.
  • The getter should be idempotent (if a getter is called twice, the second call results in the same result as the first). However, it is acceptable for a getter to compute the result each time it’s called.
3. getter應idempotent(當getter被呼叫兩次,兩次的結果應該是要相同的)。然而,getter被呼叫的時候才去計算他的結果也是可以被接受的



2014年5月23日 星期五

IOS Key-Value Coding Programming Guide 5 -- Key-Value Coding Accessor Methods

Key-Value Coding Accessor Methods

In order for key-value coding to locate the accessor methods to use for invocations of valueForKey:setValue:forKey:mutableArrayValueForKey:, and mutableSetValueForKey:, you need to implement the key-value coding accessor methods.
為了讓KVC去定位存取方法,如valueForKey:setValue:forKey:mutableArrayValueForKey:, and mutableSetValueForKey:,你必須去實現KVC的存取方法




Commonly Used Accessor Patterns

The format for an accessor method that returns a property is -<key>. The -<key> method returns an object, scalar, or a data structure. The alternate naming form -is<Key> is supported for Boolean properties.
The example in Listing 1 shows the method declaration for the hidden property using the typical convention, and Listing 2 shows the alternate format.
Listing 1  Accessor naming variations for a hidden property key
- (BOOL)hidden {
   // Implementation specific code.
   return ...;
}
Listing 2  Alternate form accessor for a hidden property key
- (BOOL)isHidden {
   // Implementation specific code.
   return ...;
}
In order for an attribute or to-one relationship property to support setValue:forKey:, an accessor in the form set<Key>: must be implemented. Listing 3shows an example accessor method for the hidden property key.
Listing 3  Accessor naming convention to support a hidden property key
- (void)setHidden:(BOOL)flag {
   // Implementation specific code.
   return;
}
If the attribute is a non-object type, you must also implement a suitable means of representing a nil value. The key-value coding methodsetNilValueForKey: method is called when you attempt to set an attribute to nil. This provides the opportunity to provide appropriate default values for your application, or handle keys that don’t have corresponding accessors in the class.
The following example sets the hidden attribute to YES when an attempt is made to set it to nil. It creates an NSNumber instance containing the Boolean value and then uses setValue:forKey: to set the new value. This maintains encapsulation of the model and ensures that any additional actions that should occur as a result of setting the value will actually occur. This is considered better practice than calling an accessor method or setting an instance variable directly.
- (void)setNilValueForKey:(NSString *)theKey {
 
    if ([theKey isEqualToString:@"hidden"]) {
        [self setValue:@YES forKey:@"hidden"];
    }
    else {
        [super setNilValueForKey:theKey];
    }
}

Collection Accessor Patterns for To-Many Properties

Although your application can implement accessor methods for to-many relationship properties using the -<key> and -set<Key>: accessor forms, you should typically only use those to create the collection object. For manipulating the contents of the collection it is best practice to implement the additional accessor methods referred to as the collection accessor methods. You then use the collection accessor methods, or a mutable collection proxy returned bymutableArrayValueForKey: or mutableSetValueForKey:.
Implementing the collection accessor methods, instead of, or in addition to, the basic getter for the relationship, can have many advantages:
  • Performance can be increased in the case of mutable to-many relationships, often significantly.
  • To-many relationships can be modeled with classes other than NSArray or NSSet by implementing the appropriate collection accessors. Implementing collection accessor methods for a property makes that property indistinguishable from an array or set when using key-value coding methods.
  • You can use the collection accessor methods directly to make modifications to the collection in a key-value observing compliant way. See Key-Value Observing Programming Guide for more information on key-value observing.
There are two variations of collection accessors: indexed accessors for ordered to-many relationships (typically represented by NSArray) and unordered accessors for relationships that don’t require an order to the members (represented by NSSet).

Indexed Accessor Pattern

The indexed accessor methods define a mechanism for counting, retrieving, adding, and replacing objects in an ordered relationship. Typically this relationship is an instance of NSArray or NSMutableArray; however, any object can implement these methods and be manipulated just as if it was an array. You are not restricted to simply implementing these methods, you can also invoke them as well to interact directly with objects in the relationship.
There are indexed accessors which return data from the collection (the getter variation) and mutable accessors that provide an interface formutableArrayValueForKey: to modify the collection.

Getter Indexed Accessors

In order to support read-only access to an ordered to-many relationship, implement the following methods:
  • -countOf<Key>. Required. This is the analogous to the NSArray primitive method count.
  • -objectIn<Key>AtIndex: or -<key>AtIndexes:. One of these methods must be implemented. They correspond to the NSArray methodsobjectAtIndex: and objectsAtIndexes:.
  • -get<Key>:range:. Implementing this method is optional, but offers additional performance gains. This method corresponds to the NSArray methodgetObjects:range:.
An implementation of the -countOf<Key> method simply returns the number of objects in the to-many relationship as an NSUInteger. The code fragment in Listing 4 illustrates the -countOf<Key> implementation for the to-many relationship property employees.
Listing 4  Example -count<Key> implementation
- (NSUInteger)countOfEmployees {
    return [self.employees count];
}
The -objectIn<Key>AtIndex: method returns the object at the specified index in the to-many relationship. The -<key>AtIndexes: accessor form returns an array of objects at the indexes specified by the NSIndexSet parameter. Only one of these two methods must be implemented.
The code fragment in Listing 5 shows -objectIn<Key>AtIndex: and -<key>AtIndexes: implementations for a to-many relationship property employees.
Listing 5  Example -objectIn<Key>AtIndex: and -<key>AtIndexes: implementations
- (id)objectInEmployeesAtIndex:(NSUInteger)index {
    return [employees objectAtIndex:index];
}
 
- (NSArray *)employeesAtIndexes:(NSIndexSet *)indexes {
    return [self.employees objectsAtIndexes:indexes];
}
If benchmarking indicates that performance improvements are required, you can also implement -get<Key>:range:. Your implementation of this accessor should return in the buffer given as the first parameter the objects that fall within the range specified by the second parameter.
Listing 6 shows an example implementation of the -get<Key>:range: accessor pattern for the to-many employees property.
Listing 6  Example -get<Key>:range: implementation
- (void)getEmployees:(Employee * __unsafe_unretained *)buffer range:(NSRange)inRange {
    // Return the objects in the specified range in the provided buffer.
    // For example, if the employees were stored in an underlying NSArray
    [self.employees getObjects:buffer range:inRange];
}

Mutable Indexed Accessors

Supporting a mutable to-many relationship with indexed accessors requires implementing additional methods. Implementing the mutable indexed accessors allow your application to interact with the indexed collection in an easy and efficient manner by using the array proxy returned bymutableArrayValueForKey:. In addition, by implementing these methods for a to-many relationship your class will be key-value observing compliant for that property (see Key-Value Observing Programming Guide).


In order to be key-value coding compliant for a mutable ordered to-many relationship you must implement the following methods:
  • -insertObject:in<Key>AtIndex: or -insert<Key>:atIndexes:. At least one of these methods must be implemented. These are analogous to theNSMutableArray methods insertObject:atIndex: and insertObjects:atIndexes:.
  • -removeObjectFrom<Key>AtIndex: or -remove<Key>AtIndexes:. At least one of these methods must be implemented. These methods correspond to the NSMutableArray methods removeObjectAtIndex: and removeObjectsAtIndexes: respectively.
  • -replaceObjectIn<Key>AtIndex:withObject: or -replace<Key>AtIndexes:with<Key>:. Optional. Implement if benchmarking indicates that performance is an issue.
The -insertObject:in<Key>AtIndex: method is passed the object to insert, and an NSUInteger that specifies the index where it should be inserted. The-insert<Key>:atIndexes: method inserts an array of objects into the collection at the indices specified by the passed NSIndexSet. You are only required to implement one of these two methods.
Listing 7 shows sample implementations of both insert accessors for the to-many employee property.
Listing 7  Example -insertObject:in<Key>AtIndex: and -insert<Key>:atIndexes: accessors
- (void)insertObject:(Employee *)employee inEmployeesAtIndex:(NSUInteger)index {
    [self.employees insertObject:employee atIndex:index];
    return;
}
 
- (void)insertEmployees:(NSArray *)employeeArray atIndexes:(NSIndexSet *)indexes {
    [self.employees insertObjects:employeeArray atIndexes:indexes];
    return;
}
The -removeObjectFrom<Key>AtIndex: method is passed an NSUInteger value specifying the index of the object to be removed from the relationship. The -remove<Key>AtIndexes: is passed an NSIndexSet specifying the indexes of the objects to be removed from the relationship. Again, you are only required to implement one of these methods.
Listing 8 shows sample implementations of -removeObjectFrom<Key>AtIndex: and -remove<Key>AtIndexes: implementations for the to-manyemployee property.
Listing 8  Example -removeObjectFrom<Key>AtIndex: and -remove<Key>AtIndexes: accessors
- (void)removeObjectFromEmployeesAtIndex:(NSUInteger)index {
    [self.employees removeObjectAtIndex:index];
}
 
- (void)removeEmployeesAtIndexes:(NSIndexSet *)indexes {
    [self.employees removeObjectsAtIndexes:indexes];
}
If benchmarking indicates that performance improvements are required, you can also implement one or both of the optional replace accessors. Your implementation of either -replaceObjectIn<Key>AtIndex:withObject: or -replace<Key>AtIndexes:with<Key>: are called when an object is replaced in a collection, rather than doing a remove and then insert.
Listing 9 shows sample implementations of -replaceObjectIn<Key>AtIndex:withObject: and -replace<Key>AtIndexes:with<Key>:implementations for the to-many employee property.
Listing 9  Example -replaceObjectIn<Key>AtIndex:withObject: and -replace<Key>AtIndexes:with<Key>: accessors
- (void)replaceObjectInEmployeesAtIndex:(NSUInteger)index
                             withObject:(id)anObject {
 
    [self.employees replaceObjectAtIndex:index withObject:anObject];
}
 
- (void)replaceEmployeesAtIndexes:(NSIndexSet *)indexes
                    withEmployees:(NSArray *)employeeArray {
 
    [self.employees replaceObjectsAtIndexes:indexes withObjects:employeeArray];
}

Unordered Accessor Pattern

The unordered accessor methods provide a mechanism for accessing and mutating objects in an unordered relationship. Typically, this relationship is an instance of NSSet or NSMutableSet. However, by implementing these accessors, any class can by used to model the relationship and be manipulated using key-value coding just as if it was an instance of NSSet.

Getter Unordered Accessors

The getter variations of the unordered accessor methods provide simple access to the relationship data. The methods return the number of objects in the collection, an enumerator to iterate over the collection objects, and a method to compare an object with the contents of the collection to see if it is already present.


In order to support read-only access to an unordered to-many relationship, you would implement the following methods:
  • -countOf<Key>. Required. This method corresponds to the NSSet method count.
  • -enumeratorOf<Key>. Required. Corresponds to the NSSet method objectEnumerator.
  • -memberOf<Key>:. Required. This method is the equivalent of the NSSet method member:
Listing 10 shows simple implementations of the necessary getter accessors that simply pass the responsibilities to the transactions property.
Listing 10  Example -countOf<Key>-enumeratorOf<Key>, and -memberOf<Key>: accessors
- (NSUInteger)countOfTransactions {
    return [self.transactions count];
}
 
- (NSEnumerator *)enumeratorOfTransactions {
    return [self.transactions objectEnumerator];
}
 
- (Transaction *)memberOfTransactions:(Transaction *)anObject {
    return [self.transactions member:anObject];
}
The -countOf<Key> accessor implementation should simply return the number of items in the relationship. The -enumeratorOf<Key> method implementation must return an NSEnumerator instance that is used to iterate over the items in the relationship. See “Enumeration: Traversing a Collection’s Elements” in Collections Programming Topics for more information about enumerators.
The -memberOf<Key>: accessor must compare the object passed as a parameter with the contents of the collection and returns the matching object as a result, or nil if no matching object is found. Your implementation of this method may use isEqual: to compare the objects, or may compare objects in another manner. The object returned may be a different object than that tested for membership, but it should be the equivalent as far as content is concerned.

Mutable Unordered Accessors

Supporting a mutable to-many relationship with unordered accessors requires implementing additional methods. Implementing the mutable unordered accessors for your application to interact with the collection in an easy and efficient manner through the use of the array proxy returned bymutableSetValueForKey:. In addition, by implementing these methods for a to-many relationship your class will be key-value observing compliant for that property (see Key-Value Observing Programming Guide).


In order to be key-value coding complaint for a mutable unordered to-many relationship you must implement the following methods:
  • -add<Key>Object: or -add<Key>:. At least one of these methods must be implemented. These are analogous to the NSMutableSet methodaddObject:.
  • -remove<Key>Object: or -remove<Key>:. At least one of these methods must be implemented. These are analogous to the NSMutableSet methodremoveObject:.
  • -intersect<Key>:. Optional. Implement if benchmarking indicates that performance is an issue. It performs the equivalent action of the NSSet methodintersectSet:.
The -add<Key>Object: and -add<Key>: implementations add a single item or a set of items to the relationship. You are only required to implement one of the methods. When adding a set of items to the relationship you should ensure that an equivalent object is not already present in the relationship. Listing 11shows an example pass-through implementation for the transactions property.
Listing 11  Example -add<Key>Object: and -add<Key>: accessors
- (void)addTransactionsObject:(Transaction *)anObject {
    [self.transactions addObject:anObject];
}
 
- (void)addTransactions:(NSSet *)manyObjects {
    [self.transactions unionSet:manyObjects];
}
Similarly, the -remove<Key>Object: and -remove<Key>: implementations remove a single item or a set of items from the relationship. Again, implementation of only one of the methods is required. Listing 12 shows an example pass-through implementation for the transactions property.
Listing 12  Example -remove<Key>Object: and -remove<Key>: accessors
- (void)removeTransactionsObject:(Transaction *)anObject {
    [self.transactions removeObject:anObject];
}
 
- (void)removeTransactions:(NSSet *)manyObjects {
    [self.transactions minusSet:manyObjects];
}
If benchmarking indicates that performance improvements are required, you can also implement the -intersect<Key>: or -set<Key>: methods (seeListing 13).
The implementation of -intersect<Key>: should remove from the relationship all the objects that aren’t common to both sets. This is the equivalent of theNSMutableSet method intersectSet:.
Listing 13  Example -intersect<Key>: and -set<Key>: implementations
- (void)intersectTransactions:(NSSet *)otherObjects {
    return [self.transactions intersectSet:otherObjects];
}