-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.xml
43 lines (43 loc) · 133 KB
/
search.xml
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title><![CDATA[AFNetworking学习总结]]></title>
<url>%2F2017%2F11%2F07%2F2017-11-07-AFNetworking%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93%2F</url>
<content type="text"><![CDATA[用了这么长时间,从来没有系统详细的研究过。今天研究一下 简介 AFNetworking is a delightful networking library for iOS and Mac OS X. It’s built on top of the Foundation URL Loading System, extending the powerful high-level networking abstractions built into Cocoa. It has a modular architecture with well-designed, feature-rich APIs that are a joy to use.Perhaps the most important feature of all, however, is the amazing community of developers who use and contribute to AFNetworking every day. AFNetworking powers some of the most popular and critically-acclaimed apps on the iPhone, iPad, and Mac.Choose AFNetworking for your next project, or migrate over your existing projects—you’ll be happy you did! 从Spec文件看AFNetworking的架构1234567891011121314151617181920212223242526272829303132333435363738394041424344 s.subspec 'Serialization' do |ss| ss.source_files = 'AFNetworking/AFURL{Request,Response}Serialization.{h,m}' ss.public_header_files = 'AFNetworking/AFURL{Request,Response}Serialization.h' ss.watchos.frameworks = 'MobileCoreServices', 'CoreGraphics' ss.ios.frameworks = 'MobileCoreServices', 'CoreGraphics' ss.osx.frameworks = 'CoreServices'ends.subspec 'Security' do |ss| ss.source_files = 'AFNetworking/AFSecurityPolicy.{h,m}' ss.public_header_files = 'AFNetworking/AFSecurityPolicy.h' ss.frameworks = 'Security'ends.subspec 'Reachability' do |ss| ss.ios.deployment_target = '7.0' ss.osx.deployment_target = '10.9' ss.tvos.deployment_target = '9.0' ss.source_files = 'AFNetworking/AFNetworkReachabilityManager.{h,m}' ss.public_header_files = 'AFNetworking/AFNetworkReachabilityManager.h' ss.frameworks = 'SystemConfiguration'ends.subspec 'NSURLSession' do |ss| ss.dependency 'AFNetworking/Serialization' ss.ios.dependency 'AFNetworking/Reachability' ss.osx.dependency 'AFNetworking/Reachability' ss.tvos.dependency 'AFNetworking/Reachability' ss.dependency 'AFNetworking/Security' ss.source_files = 'AFNetworking/AF{URL,HTTP}SessionManager.{h,m}' ss.public_header_files = 'AFNetworking/AF{URL,HTTP}SessionManager.h'ends.subspec 'UIKit' do |ss| ss.ios.deployment_target = '7.0' ss.tvos.deployment_target = '9.0' ss.dependency 'AFNetworking/NSURLSession' ss.public_header_files = 'UIKit+AFNetworking/*.h' ss.source_files = 'UIKit+AFNetworking'end 一共五个部分:NSURLSession,Serialization,Security,Reachability和UIKit.各部分的依赖关系如下:NSURLSession依赖于Serialization,Security和Reachability。 Reachability主要一个类AFNetworkReachabilityManager, 用来监控WWAN或者WiFi的可达性。该类主要使用SystemConfiguration Framework中的SCNetworkReachability这个API。 SCNetworkReachability提供的API允许应用可以检测系统当前的网络状态一级是否可以访问目标host,并且当网络状态发生变化的时候可以通过发送notifications的方式来监控。Reachability反应的只是应用把数据包可以从local computer发送到网络栈,并不能保证数据包能被收到 基本逻辑: 首先构造一个immutable的SCNetworkReachabilityRef,它是一个通过网络地址或者名称创建的引用。 异步方式,通过以下代码设置好网络状况变化的回调,并把SCNetworkReachabilityRef注册到Main RunLoop中。 123SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); 同步方式,调用SCNetworkReachabilityGetFlags获取网络状态,并执行回调和发送通知消息。 123456789101112131415161718192021__weak __typeof(self)weakSelf = self; AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) { __strong __typeof(weakSelf)strongSelf = weakSelf; strongSelf.networkReachabilityStatus = status; if (strongSelf.networkReachabilityStatusBlock) { strongSelf.networkReachabilityStatusBlock(status); } }; SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL}; SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context); SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{ SCNetworkReachabilityFlags flags; if (SCNetworkReachabilityGetFlags(self.networkReachability, &flags)) { AFPostReachabilityStatusChange(flags, callback); } }); 注:与此类似,iOS Library 的Sample Code中包含Reachability的代码,是对SCNetworkReachability的封装,比较简洁,可以直接用在项目中。它把网络状况类型缩小到了以下几种:12345 typedef enum : NSInteger { NotReachable = 0, ReachableViaWiFi, ReachableViaWWAN} NetworkStatus; SecurityAFSecurityPolicy分三种验证模式: 12345typedef NS_ENUM(NSUInteger, AFSSLPinningMode) { AFSSLPinningModeNone, AFSSLPinningModePublicKey, AFSSLPinningModeCertificate,}; AFSSLPinningModeNone不做证书绑定,信任服务端返回的证书,不做验证。 AFSSLPinningModePublicKey用证书绑定方式验证,但只验证证书里的公钥,不验证有效期等信息。(只要公钥是正确的,就能保证通信不会被窃听,因为中间人没有私钥,无法解开通过公钥加密的数据。) AFSSLPinningModeCertificate用证书绑定方式验证,第一步验证证书的域名有效期等信息,第二步对比服务器返回的证书跟客户端返回的是否一致。 Serialization AFURLRequestSerialization AFHTTPRequestSerializer AFJSONRequestSerializer AFPropertyListRequestSerializer AFURLResponseSerialization AFHTTPResponseSerializer AFJSONResponseSerializer AFXMLParserResponseSerializer AFXMLDocumentResponseSerializer (Mac OSX) AFPropertyListResponseSerializer AFImageResponseSerializer AFCompoundResponseSerializer 重点代码分析 函数NSString * AFPercentEscapedStringFromString(NSString *string) 12345678910111213141516171819202122232425262728293031323334 NSString * AFPercentEscapedStringFromString(NSString *string) { static NSString * const kAFCharactersGeneralDelimitersToEncode = @":#[]@"; // does not include "?" or "/" due to RFC 3986 - Section 3.4 static NSString * const kAFCharactersSubDelimitersToEncode = @"!$&'()*+,;="; NSMutableCharacterSet * allowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy]; [allowedCharacterSet removeCharactersInString:[kAFCharactersGeneralDelimitersToEncode stringByAppendingString:kAFCharactersSubDelimitersToEncode]]; // FIXME: https://github.com/AFNetworking/AFNetworking/pull/3028 // return [string stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet]; static NSUInteger const batchSize = 50; NSUInteger index = 0; NSMutableString *escaped = @"".mutableCopy; while (index < string.length) {#pragma GCC diagnostic push#pragma GCC diagnostic ignored "-Wgnu" NSUInteger length = MIN(string.length - index, batchSize);#pragma GCC diagnostic pop NSRange range = NSMakeRange(index, length); // To avoid breaking up character sequences such as 👴🏻👮🏽 range = [string rangeOfComposedCharacterSequencesForRange:range]; NSString *substring = [string substringWithRange:range]; NSString *encoded = [substring stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet]; [escaped appendString:encoded]; index += range.length; } return escaped;} 主要是为了减少内存消耗, 分批次对输入String进行AddingPercentEncoding处理。综合Alamofire源码可知,这是iOS 7,iOS8.1和iOS8.2的内部Bug。 rangeOfComposedCharacterSequencesForRange的用处,主要处理some of the double byte characters like emoji。 NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value)递归函数 123456789101112131415161718192021222324252627282930 NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value) { NSMutableArray *mutableQueryStringComponents = [NSMutableArray array]; NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES selector:@selector(compare:)]; if ([value isKindOfClass:[NSDictionary class]]) { NSDictionary *dictionary = value; // Sort dictionary keys to ensure consistent ordering in query string, which is important when deserializing potentially ambiguous sequences, such as an array of dictionaries for (id nestedKey in [dictionary.allKeys sortedArrayUsingDescriptors:@[ sortDescriptor ]]) { id nestedValue = dictionary[nestedKey]; if (nestedValue) { [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue((key ? [NSString stringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)]; } } } else if ([value isKindOfClass:[NSArray class]]) { NSArray *array = value; for (id nestedValue in array) { [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue([NSString stringWithFormat:@"%@[]", key], nestedValue)]; } } else if ([value isKindOfClass:[NSSet class]]) { NSSet *set = value; for (id obj in [set sortedArrayUsingDescriptors:@[ sortDescriptor ]]) { [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue(key, obj)]; } } else { [mutableQueryStringComponents addObject:[[AFQueryStringPair alloc] initWithField:key value:value]]; } return mutableQueryStringComponents;} AFHTTPRequestSerializer 12345678910111213141516 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(__unused id)object change:(NSDictionary *)change context:(void *)context{ //此处只会处理AFHTTPRequestSerializerObserverContext 类型的监听,其它的不予处理另外AFHTTPRequestSerializerObserverContext是 static void * 类型,表示此变量旨在本类的编译单元可见,指向任何类型的指针变量,赋值之后(&AFHTTPRequestSerializerObserverContext)表示指向自己地址的指针 if (context == AFHTTPRequestSerializerObserverContext) { //只判断新值,如果新值不为null,将相应的keypath添加进mutableObservedChangedKeyPaths里面 if ([change[NSKeyValueChangeNewKey] isEqual:[NSNull null]]) { [self.mutableObservedChangedKeyPaths removeObject:keyPath]; } else { [self.mutableObservedChangedKeyPaths addObject:keyPath]; } }} UIKitNSURLSession参考Networking OverviewURL Session Programming GuideNetworking Programming Topics10 Status Code DefinitionsString Programming Guide详解Javascript中的Url编码/解码]]></content>
<tags>
<tag>AFNetworking</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Android Project and Code Guidelines]]></title>
<url>%2F2017%2F04%2F09%2F2017-04-09-Android-Project-and-Code-Guidelines%2F</url>
<content type="text"><![CDATA[This is Architecture and code guidelines we use at ribot when developing for Android http://ribot.co.uk/. Project guidelinesProject structureNew projects should follow the Android Gradle project structure that is defined on the Android Gradle plugin user guide. The ribot Boilerplate project is a good reference to start from. File namingClass filesClass names are written in UpperCamelCase.For classes that extend an Android component, the name of the class should end with the name of the component;for example: SignInActivity, SignInFragment, ImageUploaderService, ChangePasswordDialog. Resources filesResources file names are written in lowercase_underscore. Drawable filesNaming conventions for drawables: Asset Type Prefix Example Action bar ab_ ab_stacked.9.png Button btn_ btn_send_pressed.9.png Dialog dialog_ dialog_top.9.png Divider divider_ divider_horizontal.9.png Icon ic_ ic_star.png Menu menu_ menu_submenu_bg.9.png Notification notification_ notification_bg.9.png Tabs tab_ tab_pressed.9.png Naming conventions for icons (taken from Android iconography guidelines): Asset Type Prefix Example Icons ic_ ic_star.png Launcher icons ic_launcher ic_launcher_calendar.png Menu icons and Action Bar icons ic_menu ic_menu_archive.png Status bar icons ic_stat_notify ic_stat_notify_msg.png Tab icons ic_tab ic_tab_recent.png Dialog icons ic_dialog ic_dialog_info.png Naming conventions for selector states: State Suffix Example Normal _normal btn_order_normal.9.png Pressed _pressed btn_order_pressed.9.png Focused _focused btn_order_focused.9.png Disabled _disabled btn_order_disabled.9.png Selected _selected btn_order_selected.9.png Layout filesLayout files should match the name of the Android components that they are intended for but moving the top level component name to the beginning. For example, if we are creating a layout for the SignInActivity, the name of the layout file should be activity_sign_in.xml. Component Class Name Layout Name Activity UserProfileActivity activity_user_profile.xml Fragment SignUpFragment fragment_sign_up.xml Dialog ChangePasswordDialog dialog_change_password.xml AdapterView item — item_person.xml Partial layout — partial_stats_bar.xml A slightly different case is when we are creating a layout that is going to be inflated by an Adapter, e.g to populate a ListView. In this case, the name of the layout should start with item_.Note that there are cases where these rules will not be possible to apply. For example, when creating layout files that are intended to be part of other layouts. In this case you should use the prefix partial_. Menu filesSimilar to layout files, menu files should match the name of the component. For example, if we are defining a menu file that is going to be used in the UserActivity, then the name of the file should be activity_user.xmlA good practice is to not include the word menu as part of the name because these files are already located in the menu directory. Values filesResource files in the values folder should be plural, e.g. strings.xml, styles.xml, colors.xml, dimens.xml, attrs.xml Code guidelinesJava language rulesDon’t ignore exceptionsYou must never do the following:12345void setServerPort(String value) { try { serverPort = Integer.parseInt(value); } catch (NumberFormatException e) { }} While you may think that your code will never encounter this error condition or that it is not important to handle it, ignoring exceptions like above creates mines in your code for someone else to trip over some day. You must handle every Exception in your code in some principled way. The specific handling varies depending on the case. - (Android code style guidelines)See alternatives here. Don’t catch generic exceptionYou should not do this:12345678try { someComplicatedIOFunction(); // may throw IOException someComplicatedParsingFunction(); // may throw ParsingException someComplicatedSecurityFunction(); // may throw SecurityException // phew, made it all the way} catch (Exception e) { // I'll just catch all exceptions handleError(); // with one generic handler!} See the reason why and some alternatives here. Don’t use finalizersWe don’t use finalizers. There are no guarantees as to when a finalizer will be called, or even that it will be called at all. In most cases, you can do what you need from a finalizer with good exception handling. If you absolutely need it, define a close() method (or the like) and document exactly when that method needs to be called. See InputStream for an example. In this case it is appropriate but not required to print a short log message from the finalizer, as long as it is not expected to flood the logs. - (Android code style guidelines) Fully qualify importsThis is bad: import foo.*;This is good: import foo.Bar;See more info here. Java style rulesFields definition and namingFields should be defined at the top of the file and they should follow the naming rules listed below. Private, non-static field names start with m. Private, static field names start with s. Other fields start with a lower case letter. Static final fields (constants) are ALL_CAPS_WITH_UNDERSCORES.Example:12345678public class MyClass { public static final int SOME_CONSTANT = 42; public int publicField; private static MyClass sSingleton; int mPackagePrivate; private int mPrivate; protected int mProtected;} Treat acronyms as words Good Bad XmlHttpRequest XMLHTTPRequest getCustomerId getCustomerID String url String URL long id long ID Use spaces for indentationUse 4 space indents for blocks:123if (x == 1) { x++;} Use 8 space indents for line wraps:12Instrument i = someLongExpression(that, wouldNotFit, on, one, line); Use standard brace styleBraces go on the same line as the code before them.1234567891011class MyClass { int func() { if (something) { // ... } else if (somethingElse) { // ... } else { // ... } }} Braces around the statements are required unless the condition and the body fit on one line.If the condition and the body fit on one line and that line is shorter than the max line length, then braces are not required, e.g.1if (condition) body(); This is bad:12if (condition) body(); // bad! AnnotationsAnnotations practicesAccording to the Android code style guide, the standard practices for some of the predefined annotations in Java are: @Override: The @Override annotation must be used whenever a method overrides the declaration or implementation from a super-class. For example, if you use the @inheritdocs Javadoc tag, and derive from a class (not an interface), you must also annotate that the method @Overrides the parent class’s method. @SuppressWarnings: The @SuppressWarnings annotation should only be used under circumstances where it is impossible to eliminate a warning. If a warning passes this “impossible to eliminate” test, the @SuppressWarnings annotation must be used, so as to ensure that all warnings reflect actual problems in the code.More information about annotation guidelines can be found here. Annotations styleClasses, Methods and Constructors When annotations are applied to a class, method, or constructor, they are listed after the documentation block and should appear as one annotation per line .1234/* This is the documentation block about the class */@AnnotationA@AnnotationBpublic class MyAnnotatedClass { } Fields Annotations applying to fields should be listed on the same line, unless the line reaches the maximum line length.1@Nullable @Mock DataManager mDataManager; Limit variable scopeThe scope of local variables should be kept to a minimum (Effective Java Item 29). By doing so, you increase the readability and maintainability of your code and reduce the likelihood of error. Each variable should be declared in the innermost block that encloses all uses of the variable.Local variables should be declared at the point they are first used. Nearly every local variable declaration should contain an initializer. If you don’t yet have enough information to initialize a variable sensibly, you should postpone the declaration until you do. - (Android code style guidelines) Order import statementsIf you are using an IDE such as Android Studio, you don’t have to worry about this because your IDE is already obeying these rules. If not, have a look below.The ordering of import statements is: Android imports Imports from third parties (com, junit, net, org) java and javax Same project importsTo exactly match the IDE settings, the imports should be: Alphabetically ordered within each grouping, with capital letters before lower case letters (e.g. Z before a). There should be a blank line between each major grouping (android, com, junit, net, org, java, javax).More info here. Logging guidelinesUse the logging methods provided by the Log class to print out error messages or other information that may be useful for developers to identify issues: Log.v(String tag, String msg) (verbose) Log.d(String tag, String msg) (debug) Log.i(String tag, String msg) (information) Log.w(String tag, String msg) (warning) Log.e(String tag, String msg) (error)As a general rule, we use the class name as tag and we define it as a static final field at the top of the file. For example:1234567public class MyClass { private static final String TAG = MyClass.class.getSimpleName(); public myMethod() { Log.e(TAG, "My error message"); }} VERBOSE and DEBUG logs must be disabled on release builds. It is also recommended to disable INFORMATION, WARNING and ERROR logs but you may want to keep them enabled if you think they may be useful to identify issues on release builds. If you decide to leave them enabled, you have to make sure that they are not leaking private information such as email addresses, user ids, etc.To only show logs on debug builds:1if (BuildConfig.DEBUG) Log.d(TAG, "The value of x is " + x); Class member orderingThere is no single correct solution for this but using a logical and consistent order will improve code learnability and readability. It is recommendable to use the following order:\ Constants Fields Constructors Override methods and callbacks (public or private) Public methods Private methods Inner classes or interfacesExample:1234567891011121314151617181920212223public class MainActivity extends Activity { private String mTitle; private TextView mTextViewTitle; public void setTitle(String title) { mTitle = title; } @Override public void onCreate() { ... } private void setUpView() { ... } static class AnInnerClass { }} If your class is extending an Android component such as an Activity or a Fragment, it is a good practice to order the override methods so that they match the component’s lifecycle. For example, if you have an Activity that implements onCreate(), onDestroy(), onPause() and onResume(), then the correct order is:12345678910111213141516public class MainActivity extends Activity { //Order matches Activity lifecycle @Override public void onCreate() {} @Override public void onResume() {} @Override public void onPause() {} @Override public void onDestroy() {}} Parameter ordering in methodsWhen programming for Android, it is quite common to define methods that take a Context. If you are writing a method like this, then the Context must be the first parameter.The opposite case are callback interfaces that should always be the last parameter.Examples:12345// Context always goes firstpublic User loadUser(Context context, int userId);// Callbacks always go lastpublic void loadUserAsync(Context context, int userId, UserCallback callback); String constants, naming, and valuesMany elements of the Android SDK such as SharedPreferences, Bundle, or Intent use a key-value pair approach so it’s very likely that even for a small app you end up having to write a lot of String constants.When using one of these components, you must define the keys as a static final fields and they should be prefixed as indicated below. Element Field Name Prefix SharedPreferences PREF_ Bundle BUNDLE_ Fragment Arguments ARGUMENT_ Intent Extra EXTRA_ Intent Action ACTION_ Note that the arguments of a Fragment - Fragment.getArguments() - are also a Bundle. However, because this is a quite common use of Bundles, we define a different prefix for them.Example:12345678// Note the value of the field is the same as the name to avoid duplication issuesstatic final String PREF_EMAIL = "PREF_EMAIL";static final String BUNDLE_AGE = "BUNDLE_AGE";static final String ARGUMENT_USER_ID = "ARGUMENT_USER_ID";// Intent-related items use full package name as valuestatic final String EXTRA_SURNAME = "com.myapp.extras.EXTRA_SURNAME";static final String ACTION_OPEN_USER = "com.myapp.action.ACTION_OPEN_USER"; Arguments in Fragments and ActivitiesWhen data is passed into an Activityor Fragment via an Intent or a Bundle, the keys for the different values must follow the rules described in the section above.When an Activity or Fragment expects arguments, it should provide a public static method that facilitates the creation of the relevant Intent or Fragment.In the case of Activities the method is usually called getStartIntent():12345public static Intent getStartIntent(Context context, User user) { Intent intent = new Intent(context, ThisActivity.class); intent.putParcelableExtra(EXTRA_USER, user); return intent;} For Fragments it is named newInstance() and handles the creation of the Fragment with the right arguments:1234567public static UserFragment newInstance(User user) { UserFragment fragment = new UserFragment; Bundle args = new Bundle(); args.putParcelable(ARGUMENT_USER, user); fragment.setArguments(args) return fragment;} Note 1: These methods should go at the top of the class before onCreate().Note 2: If we provide the methods described above, the keys for extras and arguments should be private because there is not need for them to be exposed outside the class. Line length limitCode lines should not exceed 100 characters. If the line is longer than this limit there are usually two options to reduce its length: Extract a local variable or method (preferable). Apply line-wrapping to divide a single line into multiple ones. There are two exceptions where it is possible to have lines longer than 100: Lines that are not possible to split, e.g. long URLs in comments. package and import statements. Line-wrapping strategiesThere isn’t an exact formula that explains how to line-wrap and quite often different solutions are valid. However there are a few rules that can be applied to common cases. Break at operators When the line is broken at an operator, the break comes before the operator. For example:12int longName = anotherVeryLongVariable + anEvenLongerOne - thisRidiculousLongOne + theFinalOne; Assignment Operator Exception An exception to the break at operators rule is the assignment operator =, where the line break should happen after the operator.12int longName = anotherVeryLongVariable + anEvenLongerOne - thisRidiculousLongOne + theFinalOne; Method chain case When multiple methods are chained in the same line - for example when using Builders - every call to a method should go in its own line, breaking the line before the .1Picasso.with(context).load("http://ribot.co.uk/images/sexyjoe.jpg").into(imageView); 123Picasso.with(context) .load("http://ribot.co.uk/images/sexyjoe.jpg") .into(imageView); Long parameters case When a method has many parameters or its parameters are very long, we should break the line after every comma ,1loadPicture(context, "http://ribot.co.uk/images/sexyjoe.jpg", mImageViewProfilePicture, clickListener, "Title of the picture"); 12345loadPicture(context, "http://ribot.co.uk/images/sexyjoe.jpg", mImageViewProfilePicture, clickListener, "Title of the picture"); RxJava chains stylingRx chains of operators require line-wrapping. Every operator must go in a new line and the line should be broken before the .123456789101112131415public Observable<Location> syncLocations() { return mDatabaseHelper.getAllLocations() .concatMap(new Func1<Location, Observable<? extends Location>>() { @Override public Observable<? extends Location> call(Location location) { return mRetrofitService.getLocation(location.id); } }) .retry(new Func2<Integer, Throwable, Boolean>() { @Override public Boolean call(Integer numRetries, Throwable throwable) { return throwable instanceof RetrofitError; } });} XML style rulesUse self closing tagsWhen an XML element doesn’t have any contents, you must use self closing tags.This is good:1234<TextView android:id="@+id/text_view_profile" android:layout_width="wrap_content" android:layout_height="wrap_content" /> This is bad :123456<!-- Don\'t do this! --><TextView android:id="@+id/text_view_profile" android:layout_width="wrap_content" android:layout_height="wrap_content" ></TextView> Resources namingResource IDs and names are written in lowercase_underscore. ID namingIDs should be prefixed with the name of the element in lowercase underscore. For example: Element Prefix TextView text_ ImageView image_ Button button_ Menu menu_ Image view example:1234<ImageView android:id="@+id/image_profile" android:layout_width="wrap_content" android:layout_height="wrap_content" /> Menu example:12345<menu> <item android:id="@+id/menu_done" android:title="Done" /></menu> StringsString names start with a prefix that identifies the section they belong to. For example registration_email_hint or registration_name_hint. If a string doesn’t belong to any section, then you should follow the rules below: Prefix Description error_ An error message msg_ A regular information message title_ A title, i.e. a dialog title action_ An action such as “Save” or “Create” Styles and ThemesUnless the rest of resources, style names are written in UpperCamelCase. Attributes orderingAs a general rule you should try to group similar attributes together. A good way of ordering the most common attributes is: View Id Style Layout width and layout height Other layout attributes, sorted alphabetically Remaining attributes, sorted alphabetically Tests style rulesUnit testsTest classes should match the name of the class the tests are targeting, followed by Test. For example, if we create a test class that contains tests for the DatabaseHelper, we should name it DatabaseHelperTest.Test methods are annotated with @Test and should generally start with the name of the method that is being tested, followed by a precondition and/or expected behaviour. Template: @Test void methodNamePreconditionExpectedBehaviour() Example: @Test void signInWithEmptyEmailFails()Precondition and/or expected behaviour may not always be required if the test is clear enough without them.Sometimes a class may contain a large amount of methods, that at the same time require several tests for each method. In this case, it’s recommendable to split up the test class into multiple ones. For example, if the DataManager contains a lot of methods we may want to divide it into DataManagerSignInTest, DataManagerLoadUsersTest, etc. Generally you will be able to see what tests belong together because they have common test fixtures. Espresso testsEvery Espresso test class usually targets an Activity, therefore the name should match the name of the targeted Activity followed by Test, e.g. SignInActivityTestWhen using the Espresso API it is a common practice to place chained methods in new lines.123onView(withId(R.id.view)) .perform(scrollTo()) .check(matches(isDisplayed()))]]></content>
<tags>
<tag>Android</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Android Code Style Guide]]></title>
<url>%2F2017%2F04%2F09%2F2017-04-09-Android-Code-Style-Guide%2F</url>
<content type="text"><![CDATA[This is Android Code Style for Contributors.The code styles below are strict rules, not guidelines or recommendations. Contributions to Android that do not adhere to these rules are generally not accepted. We recognize that not all existing code follows these rules, but we expect all new code to be compliant. Java Language RulesAndroid follows standard Java coding conventions with the additional rules described below. Don’t Ignore ExceptionsIt can be tempting to write code that completely ignores an exception, such as:12345void setServerPort(String value) { try { serverPort = Integer.parseInt(value); } catch (NumberFormatException e) { }} Do not do this. While you may think your code will never encounter this error condition or that it is not important to handle it, ignoring exceptions as above creates mines in your code for someone else to trigger some day. You must handle every Exception in your code in a principled way; the specific handling varies depending on the case.Anytime somebody has an empty catch clause they should have a creepy feeling. There are definitely times when it is actually the correct thing to do, but at least you have to think about it. In Java you can’t escape the creepy feeling. -James GoslingAcceptable alternatives (in order of preference) are: Throw the exception up to the caller of your method. 123void setServerPort(String value) throws NumberFormatException { serverPort = Integer.parseInt(value);} Throw a new exception that’s appropriate to your level of abstraction. 1234567void setServerPort(String value) throws ConfigurationException { try { serverPort = Integer.parseInt(value); } catch (NumberFormatException e) { throw new ConfigurationException("Port " + value + " is not valid."); }} Handle the error gracefully and substitute an appropriate value in the catch {} block. 123456789/** Set port. If value is not a valid number, 80 is substituted. */void setServerPort(String value) { try { serverPort = Integer.parseInt(value); } catch (NumberFormatException e) { serverPort = 80; // default port for server }} Catch the Exception and throw a new RuntimeException. This is dangerous, so do it only if you are positive that if this error occurs the appropriate thing to do is crash. 123456789/** Set port. If value is not a valid number, die. */void setServerPort(String value) { try { serverPort = Integer.parseInt(value); } catch (NumberFormatException e) { throw new RuntimeException("port " + value " is invalid, ", e); }} Note The original exception is passed to the constructor for RuntimeException. If your code must compile under Java 1.3, you must omit the exception that is the cause. As a last resort, if you are confident that ignoring the exception is appropriate then you may ignore it, but you must also comment why with a good reason: 123456789/** If value is not a valid number, original port number is used. */void setServerPort(String value) { try { serverPort = Integer.parseInt(value); } catch (NumberFormatException e) { // Method is documented to just ignore invalid user input. // serverPort will just be unchanged. }} Don’t Catch Generic ExceptionIt can also be tempting to be lazy when catching exceptions and do something like this:12345678try { someComplicatedIOFunction(); // may throw IOException someComplicatedParsingFunction(); // may throw ParsingException someComplicatedSecurityFunction(); // may throw SecurityException // phew, made it all the way} catch (Exception e) { // I'll just catch all exceptions handleError(); // with one generic handler!} Do not do this. In almost all cases it is inappropriate to catch generic Exception or Throwable (preferably not Throwable because it includes Error exceptions). It is very dangerous because it means that Exceptions you never expected (including RuntimeExceptions like ClassCastException) get caught in application-level error handling. It obscures the failure handling properties of your code, meaning if someone adds a new type of Exception in the code you’re calling, the compiler won’t help you realize you need to handle the error differently. In most cases you shouldn’t be handling different types of exception the same way.The rare exception to this rule is test code and top-level code where you want to catch all kinds of errors (to prevent them from showing up in a UI, or to keep a batch job running). In these cases you may catch generic Exception (or Throwable) and handle the error appropriately. Think very carefully before doing this, though, and put in comments explaining why it is safe in this place.Alternatives to catching generic Exception: Catch each exception separately as separate catch blocks after a single try. This can be awkward but is still preferable to catching all Exceptions. Beware repeating too much code in the catch blocks. Refactor your code to have more fine-grained error handling, with multiple try blocks. Split up the IO from the parsing, handle errors separately in each case. Rethrow the exception. Many times you don’t need to catch the exception at this level anyway, just let the method throw it.Remember: exceptions are your friend! When the compiler complains you’re not catching an exception, don’t scowl. Smile: the compiler just made it easier for you to catch runtime problems in your code. Don’t Use FinalizersFinalizers are a way to have a chunk of code executed when an object is garbage collected. While they can be handy for doing cleanup (particularly of external resources), there are no guarantees as to when a finalizer will be called (or even that it will be called at all).Android doesn’t use finalizers. In most cases, you can do what you need from a finalizer with good exception handling. If you absolutely need it, define a close() method (or the like) and document exactly when that method needs to be called (see InputStream for an example). In this case it is appropriate but not required to print a short log message from the finalizer, as long as it is not expected to flood the logs. Fully Qualify ImportsWhen you want to use class Bar from package foo,there are two possible ways to import it: import foo.*; Potentially reduces the number of import statements. import foo.Bar; Makes it obvious what classes are actually used and the code is more readable for maintainers.Use import foo.Bar; for importing all Android code. An explicit exception is made for java standard libraries (java.util.*, java.io.*, etc.) and unit test code (junit.framework.*). Java Library RulesThere are conventions for using Android’s Java libraries and tools. In some cases, the convention has changed in important ways and older code might use a deprecated pattern or library. When working with such code, it’s okay to continue the existing style. When creating new components however, never use deprecated libraries. Java Style RulesUse Javadoc Standard CommentsEvery file should have a copyright statement at the top, followed by package and import statements (each block separated by a blank line) and finally the class or interface declaration. In the Javadoc comments, describe what the class or interface does.12345678910111213141516171819202122232425262728293031/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.android.internal.foo;import android.os.Blah;import android.view.Yada;import java.sql.ResultSet;import java.sql.SQLException;/** * Does X and Y and provides an abstraction for Z. */public class Foo { ...} Every class and nontrivial public method you write must contain a Javadoc comment with at least one sentence describing what the class or method does. This sentence should start with a third person descriptive verb.Examples: 1234/** Returns the correctly rounded positive square root of a double value. */static double sqrt(double a) { ...} Or1234567/** * Constructs a new String by converting the specified array of * bytes using the platform's default character encoding. */public String(byte[] bytes) { ...} You do not need to write Javadoc for trivial get and set methods such as setFoo() if all your Javadoc would say is “sets Foo”. If the method does something more complex (such as enforcing a constraint or has an important side effect), then you must document it. If it’s not obvious what the property “Foo” means, you should document it.Every method you write, public or otherwise, would benefit from Javadoc. Public methods are part of an API and therefore require Javadoc. Android does not currently enforce a specific style for writing Javadoc comments, but you should follow the instructions How to Write Doc Comments for the Javadoc Tool. Write Short MethodsWhen feasible, keep methods small and focused. We recognize that long methods are sometimes appropriate, so no hard limit is placed on method length. If a method exceeds 40 lines or so, think about whether it can be broken up without harming the structure of the program. Define Fields in Standard PlacesDefine fields either at the top of the file or immediately before the methods that use them. Limit Variable ScopeKeep the scope of local variables to a minimum. By doing so, you increase the readability and maintainability of your code and reduce the likelihood of error. Each variable should be declared in the innermost block that encloses all uses of the variable.Local variables should be declared at the point they are first used. Nearly every local variable declaration should contain an initializer. If you don’t yet have enough information to initialize a variable sensibly, postpone the declaration until you do.The exception is try-catch statements. If a variable is initialized with the return value of a method that throws a checked exception, it must be initialized inside a try block. If the value must be used outside of the try block, then it must be declared before the try block, where it cannot yet be sensibly initialized:123456789101112// Instantiate class cl, which represents some sort of SetSet s = null;try { s = (Set) cl.newInstance();} catch(IllegalAccessException e) { throw new IllegalArgumentException(cl + " not accessible");} catch(InstantiationException e) { throw new IllegalArgumentException(cl + " not instantiable");}// Exercise the sets.addAll(Arrays.asList(args)); However, even this case can be avoided by encapsulating the try-catch block in a method:12345678910111213141516Set createSet(Class cl) { // Instantiate class cl, which represents some sort of Set try { return (Set) cl.newInstance(); } catch(IllegalAccessException e) { throw new IllegalArgumentException(cl + " not accessible"); } catch(InstantiationException e) { throw new IllegalArgumentException(cl + " not instantiable"); }}...// Exercise the setSet s = createSet(cl);s.addAll(Arrays.asList(args)); Loop variables should be declared in the for statement itself unless there is a compelling reason to do otherwise:123for (int i = 0; i < n; i++) { doSomething(i);} and123for (Iterator i = c.iterator(); i.hasNext(); ) { doSomethingElse(i.next());} Order Import StatementsThe ordering of import statements is: Android imports Imports from third parties (com, junit, net, org) java and javaxTo exactly match the IDE settings, the imports should be: Alphabetical within each grouping, with capital letters before lower case letters (e.g. Z before a). Separated by a blank line between each major grouping (android, com, junit, net, org, java, javax).Originally, there was no style requirement on the ordering, meaning IDEs were either always changing the ordering or IDE developers had to disable the automatic import management features and manually maintain the imports. This was deemed bad. When java-style was asked, the preferred styles varied wildly and it came down to Android needing to simply “pick an ordering and be consistent.” So we chose a style, updated the style guide, and made the IDEs obey it. We expect that as IDE users work on the code, imports in all packages will match this pattern without extra engineering effort.This style was chosen such that: The imports people want to look at first tend to be at the top (android). The imports people want to look at least tend to be at the bottom (java). Humans can easily follow the style. IDEs can follow the style.The use and location of static imports have been mildly controversial issues. Some people prefer static imports to be interspersed with the remaining imports, while some prefer them to reside above or below all other imports. Additionally, we have not yet determined how to make all IDEs use the same ordering. Since many consider this a low priority issue, just use your judgement and be consistent. Use Spaces for IndentationWe use four (4) space indents for blocks and never tabs. When in doubt, be consistent with the surrounding code.We use eight (8) space indents for line wraps, including function calls and assignments. For example, this is correct:12Instrument i = someLongExpression(that, wouldNotFit, on, one, line); and this is not correct:12Instrument i = someLongExpression(that, wouldNotFit, on, one, line); Follow Field Naming Conventions Non-public, non-static field names start with m. Static field names start with s. Other fields start with a lower case letter. Public static final fields (constants) are ALL_CAPS_WITH_UNDERSCORES.For example:12345678public class MyClass { public static final int SOME_CONSTANT = 42; public int publicField; private static MyClass sSingleton; int mPackagePrivate; private int mPrivate; protected int mProtected;} Use Standard Brace StyleBraces do not go on their own line; they go on the same line as the code before them:1234567891011class MyClass { int func() { if (something) { // ... } else if (somethingElse) { // ... } else { // ... } }} We require braces around the statements for a conditional. Exception: If the entire conditional (the condition and the body) fit on one line, you may (but are not obligated to) put it all on one line. For example, this is acceptable:123if (condition) { body();} and this is acceptable:1if (condition) body(); but this is not acceptable:12if (condition) body(); // bad! Limit Line LengthEach line of text in your code should be at most 100 characters long. While much discussion has surrounded this rule, the decision remains that 100 characters is the maximum with the following exceptions: If a comment line contains an example command or a literal URL longer than 100 characters, that line may be longer than 100 characters for ease of cut and paste. Import lines can go over the limit because humans rarely see them (this also simplifies tool writing). Use Standard Java AnnotationsAnnotations should precede other modifiers for the same language element. Simple marker annotations (e.g. @Override) can be listed on the same line with the language element. If there are multiple annotations, or parameterized annotations, they should each be listed one-per-line in alphabetical order.Android standard practices for the three predefined annotations in Java are: @Deprecated: The @Deprecated annotation must be used whenever the use of the annotated element is discouraged. If you use the @Deprecated annotation, you must also have a @deprecated Javadoc tag and it should name an alternate implementation. In addition, remember that a @Deprecated method is still supposed to work. If you see old code that has a @deprecated Javadoc tag, please add the @Deprecated annotation. @Override: The @Override annotation must be used whenever a method overrides the declaration or implementation from a super-class. For example, if you use the @inheritdocs Javadoc tag, and derive from a class (not an interface), you must also annotate that the method @Overrides the parent class’s method. @SuppressWarnings: The @SuppressWarnings annotation should be used only under circumstances where it is impossible to eliminate a warning. If a warning passes this “impossible to eliminate” test, the @SuppressWarnings annotation must be used, so as to ensure that all warnings reflect actual problems in the code. When a @SuppressWarnings annotation is necessary, it must be prefixed with a TODO comment that explains the “impossible to eliminate” condition. This will normally identify an offending class that has an awkward interface. For example:123// TODO: The third-party class com.third.useful.Utility.rotate() needs generics@SuppressWarnings("generic-cast")List<String> blix = Utility.rotate(blax); When a @SuppressWarnings annotation is required, the code should be refactored to isolate the software elements where the annotation applies. Treat Acronyms as WordsTreat acronyms and abbreviations as words in naming variables, methods, and classes to make names more readable: Good Bad XmlHttpRequest XMLHTTPRequest getCustomerId getCustomerID class Html class HTML String url String URL long id long ID As both the JDK and the Android code bases are very inconsistent around acronyms, it is virtually impossible to be consistent with the surrounding code. Therefore, always treat acronyms as words. Use TODO CommentsUse TODO comments for code that is temporary, a short-term solution, or good-enough but not perfect. TODOs should include the string TODO in all caps, followed by a colon:1// TODO: Remove this code after the UrlTable2 has been checked in. and1// TODO: Change this to use a flag instead of a constant. Log SparinglyWhile logging is necessary, it has a significantly negative impact on performance and quickly loses its usefulness if not kept reasonably terse. The logging facilities provides five different levels of logging: ERROR: Use when something fatal has happened, i.e. something will have user-visible consequences and won’t be recoverable without explicitly deleting some data, uninstalling applications, wiping the data partitions or reflashing the entire device (or worse). This level is always logged. Issues that justify some logging at the ERROR level are typically good candidates to be reported to a statistics-gathering server. WARNING: Use when something serious and unexpected happened, i.e. something that will have user-visible consequences but is likely to be recoverable without data loss by performing some explicit action, ranging from waiting or restarting an app all the way to re-downloading a new version of an application or rebooting the device. This level is always logged. Issues that justify some logging at the WARNING level might also be considered for reporting to a statistics-gathering server. INFORMATIVE: Use to note that something interesting to most people happened, i.e. when a situation is detected that is likely to have widespread impact, though isn’t necessarily an error. Such a condition should only be logged by a module that reasonably believes that it is the most authoritative in that domain (to avoid duplicate logging by non-authoritative components). This level is always logged. DEBUG: Use to further note what is happening on the device that could be relevant to investigate and debug unexpected behaviors. You should log only what is needed to gather enough information about what is going on about your component. If your debug logs are dominating the log then you probably should be using verbose logging. This level will be logged, even on release builds, and is required to be surrounded by an if (LOCAL_LOG) or if (LOCAL_LOGD) block, where LOCAL_LOG[D] is defined in your class or subcomponent, so that there can exist a possibility to disable all such logging. There must therefore be no active logic in an if (LOCAL_LOG) block. All the string building for the log also needs to be placed inside the if (LOCAL_LOG) block. The logging call should not be re-factored out into a method call if it is going to cause the string building to take place outside of the if (LOCAL_LOG) block. There is some code that still says if (localLOGV). This is considered acceptable as well, although the name is nonstandard. VERBOSE: Use for everything else. This level will only be logged on debug builds and should be surrounded by an if (LOCAL_LOGV) block (or equivalent) so it can be compiled out by default. Any string building will be stripped out of release builds and needs to appear inside the if (LOCAL_LOGV) block.Notes: Within a given module, other than at the VERBOSE level, an error should only be reported once if possible. Within a single chain of function calls within a module, only the innermost function should return the error, and callers in the same module should only add some logging if that significantly helps to isolate the issue. In a chain of modules, other than at the VERBOSE level, when a lower-level module detects invalid data coming from a higher-level module, the lower-level module should only log this situation to the DEBUG log, and only if logging provides information that is not otherwise available to the caller. Specifically, there is no need to log situations where an exception is thrown (the exception should contain all the relevant information), or where the only information being logged is contained in an error code. This is especially important in the interaction between the framework and applications, and conditions caused by third-party applications that are properly handled by the framework should not trigger logging higher than the DEBUG level. The only situations that should trigger logging at the INFORMATIVE level or higher is when a module or application detects an error at its own level or coming from a lower level. When a condition that would normally justify some logging is likely to occur many times, it can be a good idea to implement some rate-limiting mechanism to prevent overflowing the logs with many duplicate copies of the same (or very similar) information. Losses of network connectivity are considered common, fully expected, and should not be logged gratuitously. A loss of network connectivity that has consequences within an app should be logged at the DEBUG or VERBOSE level (depending on whether the consequences are serious enough and unexpected enough to be logged in a release build). Having a full filesystem on a filesystem that is accessible to or on behalf of third-party applications should not be logged at a level higher than INFORMATIVE. Invalid data coming from any untrusted source (including any file on shared storage, or data coming through just about any network connection) is considered expected and should not trigger any logging at a level higher than DEBUG when it’s detected to be invalid (and even then logging should be as limited as possible). Keep in mind that the + operator, when used on Strings, implicitly creates a StringBuilder with the default buffer size (16 characters) and potentially other temporary String objects, i.e. that explicitly creating StringBuilders isn’t more expensive than relying on the default ‘+’ operator (and can be a lot more efficient in fact). Keep in mind that code that calls Log.v() is compiled and executed on release builds, including building the strings, even if the logs aren’t being read. Any logging that is meant to be read by other people and to be available in release builds should be terse without being cryptic, and should be reasonably understandable. This includes all logging up to the DEBUG level. When possible, logging should be kept on a single line if it makes sense. Line lengths up to 80 or 100 characters are perfectly acceptable, while lengths longer than about 130 or 160 characters (including the length of the tag) should be avoided if possible. Logging that reports successes should never be used at levels higher than VERBOSE. Temporary logging used to diagnose an issue that is hard to reproduce should be kept at the DEBUG or VERBOSE level and should be enclosed by if blocks that allow for disabling it entirely at compile time. Be careful about security leaks through the log. Private information should be avoided. Information about protected content must definitely be avoided. This is especially important when writing framework code as it’s not easy to know in advance what will and will not be private information or protected content. System.out.println() (or printf() for native code) should never be used. System.out and System.err get redirected to /dev/null, so your print statements will have no visible effects. However, all the string building that happens for these calls still gets executed. The golden rule of logging is that your logs may not unnecessarily push other logs out of the buffer, just as others may not push out yours. Be ConsistentOur parting thought: BE CONSISTENT. If you’re editing code, take a few minutes to look at the surrounding code and determine its style. If that code uses spaces around the if clauses, you should too. If the code comments have little boxes of stars around them, make your comments have little boxes of stars around them too.The point of having style guidelines is to have a common vocabulary of coding, so people can concentrate on what you’re saying, rather than on how you’re saying it. We present global style rules here so people know the vocabulary, but local style is also important. If the code you add to a file looks drastically different from the existing code around it, it throws readers out of their rhythm when they go to read it. Try to avoid this. Javatests Style RulesFollow test method naming conventions and use an underscore to separate what is being tested from the specific case being tested. This style makes it easier to see exactly what cases are being tested. For example:1234567testMethod_specificCase1 testMethod_specificCase2void testIsDistinguishable_protanopia() { ColorMatcher colorMatcher = new ColorMatcher(PROTANOPIA) assertFalse(colorMatcher.isDistinguishable(Color.RED, Color.BLACK)) assertTrue(colorMatcher.isDistinguishable(Color.X, Color.Y))}]]></content>
<tags>
<tag>Android</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Google Objective-C Style Guide]]></title>
<url>%2F2017%2F04%2F08%2F2017-04-08-Google-Objective-C-Style-Guide%2F</url>
<content type="text"><![CDATA[This is Google Objective-C Style Guide. BackgroundObjective-C is a very dynamic, object-oriented extension of C. It’s designed to be easy to use and read, while enabling sophisticated object-oriented design. It is the primary development language for new applications on Mac OS X and the iPhone.Cocoa is one of the main application frameworks on Mac OS X. It is a collection of Objective-C classes that provide for rapid development of full-featured Mac OS X applications.Apple has already written a very good, and widely accepted, coding guide for Objective-C. Google has also written a similar guide for C++. This Objective-C guide aims to be a very natural combination of Apple’s and Google’s general recommendations. So, before reading this guide, please make sure you’ve read: Apple’s Cocoa Coding Guidelines Google’s Open Source C ++ Style Guide The purpose of this document is to describe the Objective-C (and Objective-C++) coding guidelines and practices that should be used for all Mac OS X code. Many of these guidelines have evolved and been proven over time on other projects and teams. Open-source projects developed by Google conform to the requirements in this guide.Note that this guide is not an Objective-C tutorial. We assume that the reader is familiar with the language. If you are new to Objective-C or need a refresher, please read Programming with Objective-C . ExampleThey say an example is worth a thousand words so let’s start off with an example that should give you a feel for the style, spacing, naming, etc.An example header file, demonstrating the correct commenting and spacing for an @interface declaration 12345678910111213141516171819202122232425262728293031323334353637383940414243444546#import "Foo.h"@implementation Foo { NSString *_bar; NSString *_foo;}+ (instancetype)fooWithBar:(NSString *)bar { return [[[self alloc] initWithBar:bar] autorelease];}// Must always override super's designated initializer.- (instancetype)init { return [self initWithBar:nil];}- (instancetype)initWithBar:(NSString *)bar { if ((self = [super init])) { _bar = [bar copy]; _bam = [[NSString alloc] initWithFormat:@"hi %d", 3]; } return self;}- (void)dealloc { [_bar release]; [_bam release]; [super dealloc];}- (NSString *)bar { return _bar;}- (void)setBar:(NSString *)bar { [_bar autorelease]; _bar = [bar copy];}- (BOOL)doWorkWithBlah:(NSString *)blah { // ... return NO;}@end An example source file, demonstrating the correct commenting and spacing for the @implementation of an interface. It also includes the reference implementations for important methods like getters and setters,init, and dealloc. 12345678910111213141516171819202122232425262728293031323334353637383940414243444546#import "Foo.h"@implementation Foo { NSString *_bar; NSString *_foo;}+ (instancetype)fooWithBar:(NSString *)bar { return [[[self alloc] initWithBar:bar] autorelease];}// Must always override super's designated initializer.- (instancetype)init { return [self initWithBar:nil];}- (instancetype)initWithBar:(NSString *)bar { if ((self = [super init])) { _bar = [bar copy]; _bam = [[NSString alloc] initWithFormat:@"hi %d", 3]; } return self;}- (void)dealloc { [_bar release]; [_bam release]; [super dealloc];}- (NSString *)bar { return _bar;}- (void)setBar:(NSString *)bar { [_bar autorelease]; _bar = [bar copy];}- (BOOL)doWorkWithBlah:(NSString *)blah { // ... return NO;}@end Blank lines before and after @interface, @implementation, and @end are optional. If your @interface declares instance variables, a blank line should come after the closing brace (}). Unless an interface or implementation is very short, such as when declaring a handful of private methods or a bridge class, adding blank lines usually helps readability. Spacing And FormattingSpaces vs. TabsUse only spaces, and indent 2 spaces at a time.We use spaces for indentation. Do not use tabs in your code. You should set your editor to emit spaces when you hit the tab key. Line LengthThe maximum line length for Objective-C and Objective-C++ files is 100 columns. Projects may opt to use an 80 column limit for consistency with the C++ style guide.You can make violations easier to spot by enabling Preferences > Text Editing > Page guide at column: 100 in Xcode. Method Declarations and DefinitionsOne space should be used between the - or + and the return type, and no spacing in the parameter list except between parameters.Methods should look like this:123- (void)doSomethingWithString:(NSString *)theString { ...} The spacing before the asterisk is optional. When adding new code, be consistent with the surrounding file’s style.If you have too many parameters to fit on one line, giving each its own line is preferred. If multiple lines are used, align each using the colon before the parameter.12345- (void)doSomethingWith:(GTMFoo *)theFoo rect:(NSRect)theRect interval:(float)theInterval { ...} When the first keyword is shorter than the others, indent the later lines by at least four spaces, maintaining colon alignment:123456- (void)short:(GTMFoo *)theFoo longKeyword:(NSRect)theRect evenLongerKeyword:(float)theInterval error:(NSError **)theError { ...} Method InvocationsMethod invocations should be formatted much like method declarations. When there’s a choice of formatting styles, follow the convention already used in a given source file.Invocations should have all arguments on one line:1[myObject doFooWith:arg1 name:arg2 error:arg3]; or have one argument per line, with colons aligned:123[myObject doFooWith:arg1 name:arg2 error:arg3]; Don’t use any of these styles:123456789[myObject doFooWith:arg1 name:arg2 // some lines with >1 arg error:arg3];[myObject doFooWith:arg1 name:arg2 error:arg3];[myObject doFooWith:arg1 name:arg2 // aligning keywords instead of colons error:arg3]; As with declarations and definitions, when the first keyword is shorter than the others, indent the later lines by at least four spaces, maintaining colon alignment:1234[myObj short:arg1 longKeyword:arg2 evenLongerKeyword:arg3 error:arg4]; Invocations containing inlined blocks may have their segments left-aligned at a four space indent. @public and @privateThe @public and@private access modifiers should be indented by 1 space.This is similar to public, private, and protected in C++.1234567@interface MyClass : NSObject { @public ... @private ...}@end ExceptionsFormat exceptions with each @ label on its own line and a space between the @ label and the opening brace ({), as well as between the @catch and the caught object declaration.If you must use Obj-C exceptions, format them as follows. However, see Avoid Throwing Exceptions for reasons why you should not be using exceptions.123456789@try { foo();}@catch (NSException *ex) { bar(ex);}@finally { baz();} ProtocolsThere should not be a space between the type identifier and the name of the protocol encased in angle brackets.This applies to class declarations, instance variables, and method declarations. For example:123456@interface MyProtocoledClass : NSObject<NSWindowDelegate> { @private id<MyFancyDelegate> _delegate;}- (void)setDelegate:(id<MyFancyDelegate>)aDelegate;@end BlocksCode inside blocks should be indented four spaces.There are several appropriate style rules, depending on how long the block is: If the block can fit on one line, no wrapping is necessary. If it has to wrap, the closing brace should line up with the first character of the line on which the block is declared. Code within the block should be indented four spaces. If the block is large, e.g. more than 20 lines, it is recommended to move it out-of-line into a local variable. If the block takes no parameters, there are no spaces between the characters ^{. If the block takes parameters, there is no space between the ^( characters, but there is one space between the ) { characters. Invocations containing inlined blocks may have their segments left-aligned at a four-space indent. This helps when invocations contain multiple inlined blocks. Two space indents inside blocks are also allowed, but should only be used when it’s consistent with the rest of the project’s code.123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657// The entire block fits on one line.[operation setCompletionBlock:^{ [self onOperationDone]; }];// The block can be put on a new line, indented four spaces, with the// closing brace aligned with the first character of the line on which// block was declared.[operation setCompletionBlock:^{ [self.delegate newDataAvailable];}];// Using a block with a C API follows the same alignment and spacing// rules as with Objective-C.dispatch_async(_fileIOQueue, ^{ NSString* path = [self sessionFilePath]; if (path) { // ... }});// An example where the parameter wraps and the block declaration fits// on the same line. Note the spacing of |^(SessionWindow *window) {|// compared to |^{| above.[[SessionService sharedService] loadWindowWithCompletionBlock:^(SessionWindow *window) { if (window) { [self windowDidLoad:window]; } else { [self errorLoadingWindow]; } }];// An example where the parameter wraps and the block declaration does// not fit on the same line as the name.[[SessionService sharedService] loadWindowWithCompletionBlock: ^(SessionWindow *window) { if (window) { [self windowDidLoad:window]; } else { [self errorLoadingWindow]; } }];// Large blocks can be declared out-of-line.void (^largeBlock)(void) = ^{ // ...};[_operationQueue addOperationWithBlock:largeBlock];// An example with multiple inlined blocks in one invocation.[myObject doSomethingWith:arg1 firstBlock:^(Foo *a) { // ... } secondBlock:^(Bar *b) { // ... }]; Container LiteralsFor projects using Xcode 4.4 or later and clang, the use of container (array and dictionary) literals is encouraged. If split across multiple lines, the contents should be indented two spaces.If the collection fits on one line, put a single space after the opening and before the closing brackets.123NSArray* array = @[ [foo description], @"Another String", [bar description] ];NSDictionary* dict = @{ NSForegroundColorAttributeName : [NSColor redColor] }; Not:123NSArray* array = @[[foo description], [bar description]];NSDictionary* dict = @{NSForegroundColorAttributeName: [NSColor redColor]}; If the collection spans more than a single line, place the opening bracket on the same line as the declaration, indent the body by two spaces, and place the closing bracket on a new line that is indented to the same level as the opening bracket.1234567891011NSArray* array = @[ @"This", @"is", @"an", @"array"];NSDictionary* dictionary = @{ NSFontAttributeName : [NSFont fontWithName:@"Helvetica-Bold" size:12], NSForegroundColorAttributeName : fontColor}; For dictionary literals, there should be one space before the colon and at least one space after it (to optionally align the values).123456789NSDictionary* option1 = @{ NSFontAttributeName : [NSFont fontWithName:@"Helvetica-Bold" size:12], NSForegroundColorAttributeName : fontColor};NSDictionary* option2 = @{ NSFontAttributeName : [NSFont fontWithName:@"Arial" size:12], NSForegroundColorAttributeName : fontColor}; The following are all incorrect:12345678910111213141516// There should be a space before the colon.NSDictionary* wrong = @{ AKey: @"b", BLongerKey: @"c",};// The items should each be on a new line, or the entire expression// should fit on one line.NSDictionary* alsoWrong= @{ AKey : @"a", BLongerKey : @"b" };// There should be no variable space before the colon, only after.NSDictionary* stillWrong = @{ AKey : @"b", BLongerKey : @"c",}; NamingNaming rules are very important in maintainable code. Objective-C method names tend to be very long, but this has the benefit that a block of code can almost read like prose, thus rendering many comments unnecessary.When writing pure Objective-C code, we mostly follow standard Objective-C naming rules. These naming guidelines may differ significantly from those outlined in the C++ style guide. For example, Google’s C++ style guide recommends the use of underscores between words in variable names, whereas this guide recommends the use of intercaps, which is standard in the Objective-C community.Any class, category, method, or variable name may use all capitals for initialisms within the name. This follows Apple’s standard of using all capitals within a name for initialisms such as URL, TIFF, and EXIF.When writing Objective-C++, however, things are not so cut and dry. Many projects need to implement cross-platform C++ APIs with some Objective-C or Cocoa, or bridge between a C++ back-end and a native Cocoa front-end. This leads to situations where the two guides are directly at odds.Our solution is that the style follows that of the method/function being implemented. If you’re in an @implementation block, use the Objective-C naming rules. If you’re implementing a method for a C++ class, use the C++ naming rules. This avoids the situation where instance variable and local variable naming rules are mixed within a single function, which would be a serious detriment to readability. File NamesFile names should reflect the name of the class implementation that they contain—including case. Follow the convention that your project uses.File extensions should be as follows: | .h | C/C++/Objective-C header file || .m | Objective-C implementation file || .mm | Objective-C++ implementation file || .cc | Pure C++ implementation file || .c | C implementation file | File names for categories should include the name of the class being extended, e.g. GTMNSString+Utils.h or GTMNSTextView+Autocomplete.h Objective-C++Within a source file, Objective-C++ follows the style of the function/method you’re implementing.In order to minimize clashes between the differing naming styles when mixing Cocoa/Objective-C and C++, follow the style of the method being implemented. If you’re in an @implementation block, use the Objective-C naming rules. If you’re implementing a method for a C++ class, use the C++ naming rules.12345678910111213141516171819202122232425262728293031323334353637// file: cross_platform_header.hclass CrossPlatformAPI { public: ... int DoSomethingPlatformSpecific(); // impl on each platform private: int an_instance_var_;};// file: mac_implementation.mm#include "cross_platform_header.h"// A typical Objective-C class, using Objective-C naming.@interface MyDelegate : NSObject { @private int _instanceVar; CrossPlatformAPI* _backEndObject;}- (void)respondToSomething:(id)something;@end@implementation MyDelegate- (void)respondToSomething:(id)something { // bridge from Cocoa through our C++ backend _instanceVar = _backEndObject->DoSomethingPlatformSpecific(); NSString* tempString = [NSString stringWithFormat:@"%d", _instanceVar]; NSLog(@"%@", tempString);}@end// The platform-specific implementation of the C++ class, using// C++ naming.int CrossPlatformAPI::DoSomethingPlatformSpecific() { NSString* temp_string = [NSString stringWithFormat:@"%d", an_instance_var_]; NSLog(@"%@", temp_string); return [temp_string intValue];} Class NamesClass names (along with category and protocol names) should start as uppercase and use mixed case to delimit words.When designing code to be shared across multiple applications, prefixes are acceptable and recommended (e.g. GTMSendMessage). Prefixes are also recommended for classes of large applications that depend on external libraries. Category NamesCategory names should start with a 2 or 3 character prefix identifying the category as part of a project or open for general use. The category name should incorporate the name of the class it’s extending.For example, if we want to create a category on NSString for parsing, we would put the category in a file named GTMNSString+Parsing.h, and the category itself would be named GTMStringParsingAdditions (yes, we know the file name and the category name do not match, but this file could have many separate categories related to parsing). Methods in that category should share the prefix (gtm_myCategoryMethodOnAString:) in order to prevent collisions in Objective-C which only has a single namespace. If the code isn’t meant to be shared and/or doesn’t run in a different address-space, the method naming isn’t quite as important.There should be a single space between the class name and the opening parenthesis of the category.12345678910// Extending a framework class:@interface NSString (GTMStringParsingAdditions)- (NSString *)gtm_foobarString;@end// Making your methods and properties private:@interface FoobarViewController ()@property(nonatomic, retain) NSView *dongleView;- (void)performLayout;@end Objective-C Method NamesMethod names should start as lowercase and then use mixed case. Each named parameter should also start as lowercase.The method name should read like a sentence if possible, meaning you should choose parameter names that flow with the method name. (e.g. convertPoint:fromRect:or replaceCharactersInRange:withString:). See Apple’s Guide to Naming Methods for more details.Accessor methods should be named the same as the variable they’re “getting”, but they should not be prefixed with the word “get”. For example:- (id)getDelegate; // AVOID- (id)delegate; // GOODThis is for Objective-C methods only. C++ method names and functions continue to follow the rules set in the C++ style guide. Variable NamesVariables names start with a lowercase and use mixed case to delimit words. Instance variables have leading underscores. For example: myLocalVariable, _myInstanceVariable. Common Variable NamesDo not use Hungarian notation for syntactic attributes, such as the static type of a variable (int or pointer). Give as descriptive a name as possible, within reason. Don’t worry about saving horizontal space as it is far more important to make your code immediately understandable by a new reader. For example:123456int w;int nerr;int nCompConns;tix = [[NSMutableArray alloc] init];obj = [someObject object];p = [network port]; 12345int numErrors;int numCompletedConnections;tickets = [[NSMutableArray alloc] init];userInfo = [someObject object];port = [network port]; Instance VariablesInstance variables are mixed case and should be prefixed with an underscore e.g. _usernameTextField. Note that historically the convention was to put the underscore at the end of the name, and projects may opt to continue using trailing underscores in new code in order to maintain consistency within their codebase (see the Historical Notes section). It is recommended you leave old code as-is, unless doing so would create inconsistency within a class. ConstantsConstant names (#defines, enums, const local variables, etc.) should start with a lowercase k and then use mixed case to delimit words. For example:123456const int kNumberOfFiles = 12;NSString *const kUserKey = @"kUserKey";enum DisplayTinge { kDisplayTingeGreen = 1, kDisplayTingeBlue = 2}; Because Objective-C does not provide namespacing, constants with global scope should have an appropriate prefix to minimize the chance of name collision, typically like kClassNameFoo. CommentsThough a pain to write, they are absolutely vital to keeping our code readable. The following rules describe what you should comment and where. But remember: while comments are very important, the best code is self-documenting. Giving sensible names to types and variables is much better than using obscure names and then trying to explain them through comments.When writing your comments, write for your audience: the next contributor who will need to understand your code. Be generous—the next one may be you!Remember that all of the rules and conventions listed in the C++ Style Guide are in effect here, with a few additional points, below. File CommentsA file may optionally start with a description of its contents.Every file should contain the following items, in order: license boilerplate if neccessary. Choose the appropriate boilerplate for the license used by the project (e.g. Apache 2.0, BSD, LGPL, GPL). a basic description of the contents of the file if necessary. If you make significant changes to a file with an author line, consider deleting the author line since revision history already provides a more detailed and accurate record of authorship. Declaration CommentsEvery interface, category, and protocol declaration should have an accompanying comment describing its purpose and how it fits into the larger picture.123456// A delegate for NSApplication to handle notifications about app// launch and shutdown. Owned by the main app controller.@interface MyAppDelegate : NSObject { ...}@end If you have already described an interface in detail in the comments at the top of your file feel free to simply state “See comment at top of file for a complete description”, but be sure to have some sort of comment.Additionally, each method in the public interface should have a comment explaining its function, arguments, return value, and any side effects.Document the synchronization assumptions the class makes, if any. If an instance of the class can be accessed by multiple threads, take extra care to document the rules and invariants surrounding multithreaded use. Implementation CommentsUse vertical bars to quote variable names and symbols in comments rather than quotes or naming the symbol inline.This helps eliminate ambiguity, especially when the symbol is a common word that might make the sentence read like it was poorly constructed. E.g. for a symbol “count”:// Sometimes we need |count| to be less than zero.or when quoting something which already contains quotes// Remember to call |StringWithoutSpaces("foo bar baz")| Object OwnershipMake the pointer ownership model as explicit as possible when it falls outside the most common Objective-C usage idioms. Manual Reference CountingInstance variables which are pointers to objects derived from NSObject are presumed to be retained, and should be either commented as weak or declared with the __weak lifetime qualifier when applicable. Similarly, declared properties must specify an assign property attribute if they are not retained by the class. An exception is instance variables labeled as IBOutlets in desktop Mac software, which are presumed to not be retained.Where instance variables are pointers to Core Foundation, C++, and other non-Objective-C objects, they should always be declared with strong and weak comments to indicate which pointers are and are not retained. Core Foundation and other non-Objective-C object pointers require explicit memory management, even when building for automatic reference counting or garbage collection.Examples of strong and weak declarations:1234567891011121314@interface MyDelegate : NSObject { @private IBOutlet NSButton *_okButton; // Normal NSControl; implicitly weak on Mac only AnObjcObject* _doohickey; // My doohickey __weak MyObjcParent *_parent; // So we can send msgs back (owns me) // non-NSObject pointers... CWackyCPPClass *_wacky; // Strong, some cross-platform object CFDictionaryRef *_dict; // Strong}@property(strong, nonatomic) NSString *doohickey;@property(weak, nonatomic) NSString *parent;@end Automatic Reference CountingObject ownership and lifetime are explicit when using ARC, so no additional comments are required. Cocoa and Objective-C FeaturesInstance Variables In Headers Should Be @privateInstance variables should typically be declared in implementation files or auto-synthesized by properties. When ivars are declared in a header file, they should be marked @private.12345@interface MyClass : NSObject { @private id _myInstanceVariable;}@end Identify Designated InitializerComment and clearly identify your designated initializer.It is important for those who might be subclassing your class that the designated initializer be clearly identified. That way, they only need to subclass a single initializer (of potentially several) to guarantee their subclass’ initializer is called. It also helps those debugging your class in the future understand the flow of initialization code if they need to step through it. Override Designated InitializerWhen writing a subclass that requires an init... method, make sure you override the superclass’ designated initializer.If you fail to override the superclass’ designated initializer, your initializer may not be called in all cases, leading to subtle and very difficult to find bugs. Overridden NSObject Method PlacementIt is strongly recommended and typical practice to place overridden methods of NSObject at the top of an @implementation.This commonly applies (but is not limited) to the init..., copyWithZone:, and deallocmethods. init... methods should be grouped together, followed by other NSObject methods.Convenience class methods for creating instances may precede the NSObject methods. InitializationDon’t initialize variables to 0 or nil in the init method; it’s redundant.All memory for a newly allocated object is initialized to 0 (except for isa), so don’t clutter up the init method by re-initializing variables to 0 or nil. Avoid +newDo not invoke the NSObject class method new, nor override it in a subclass. Instead, use alloc and init methods to instantiate retained objects.Modern Objective-C code explicitly calls alloc and an init method to create and retain an object. As the newclass method is rarely used, it makes reviewing code for correct memory management more difficult. Keep the Public API SimpleKeep your class simple; avoid “kitchen-sink” APIs. If a method doesn’t need to be public, don’t make it so. Use a private category to prevent cluttering the public header.Unlike C++, Objective-C doesn’t have a way to differentiate between public and private methods—everything is public. As a result, avoid placing methods in the public API unless they are actually expected to be used by a consumer of the class. This helps reduce the likelihood they’ll be called when you’re not expecting it. This includes methods that are being overridden from the parent class. For internal implementation methods, use a category defined in the implementation file as opposed to adding them to the public header.12345678910111213#import "GTMFoo.h"@interface GTMFoo (PrivateDelegateHandling)- (NSString *)doSomethingWithDelegate; // Declare private method@end@implementation GTMFoo (PrivateDelegateHandling)...- (NSString *)doSomethingWithDelegate { // Implement this method}...@end If you are using Objective-C 2.0, you should instead declare your private category using a class extension, for example: @interface GMFoo () { ... }which will guarantee that the declared methods are implemented in the @implementation section by issuing a compiler warning if they are not.Again, “private” methods are not really private. You could accidentally override a superclass’s “private” method, thus making a very difficult bug to squash. In general, private methods should have a fairly unique name that will prevent subclasses from unintentionally overriding them.Finally, Objective-C categories are a great way to segment a large @implementation section into more understandable chunks and to add new, application-specific functionality to the most appropriate class. For example, instead of adding “middle truncation” code to a random object in your app, make a new category on NSString). #import and #include\#import Objective-C/Objective-C++ headers, and #include C/C++ headers.Choose between #import and #include based on the language of the header that you are including.• When including a header that uses Objective-C or Objective-C++, use #import.• When including a standard C or C++ header, use #include. The header should provide its own #define guard.Some Objective-C headers lack #define guards, and expect to be included only by #import. As Objective-C headers may only be included in Objective-C source files and other Objective-C headers, using #import across the board is appropriate.Standard C and C++ headers without any Objective-C in them can expect to be included by ordinary C and C++ files. Since there is no #import in standard C or C++, such files will be included by #include in those cases. Using #include for them in Objective-C source files as well means that these headers will always be included with the same semantics.This rule helps avoid inadvertent errors in cross-platform projects. A Mac developer introducing a new C or C++ header might forget to add #define guards, which would not cause problems on the Mac if the new header were included with #import, but would break builds on other platforms where #include is used. Being consistent by using #include on all platforms means that compilation is more likely to succeed everywhere or fail everywhere, and avoids the frustration of files working only on some platforms.1234#import <Cocoa/Cocoa.h>#include <CoreFoundation/CoreFoundation.h>#import "GTMFoo.h"#include "base/basictypes.h" Use Root FrameworksInclude root frameworks over individual files.While it may seem tempting to include individual system headers from a framework such as Cocoa or Foundation, in fact it’s less work on the compiler if you include the top-level root framework. The root framework is generally pre-compiled and can be loaded much more quickly. In addition, remember to use #import rather than #include for Objective-C frameworks.1234#import <Foundation/Foundation.h> // good#import <Foundation/NSArray.h> // avoid#import <Foundation/NSString.h>... Prefer To autorelease At Time of CreationWhen creating new temporary objects, autorelease them on the same line as you create them rather than a separate release later in the same method.While ever so slightly slower, this prevents someone from accidentally removing the release or inserting a return before it and introducing a memory leak. E.g.:1234567// AVOID (unless you have a compelling performance reason)MyController* controller = [[MyController alloc] init];// ... code here that might return ...[controller release];// BETTERMyController* controller = [[[MyController alloc] init] autorelease]; Autorelease Then RetainAssignment of objects follows the autorelease then retain pattern.When assigning a new object to a variable, one must first release the old object to avoid a memory leak. There are several “correct” ways to handle this. We’ve chosen the “autorelease then retain” approach because it’s less prone to error. Be aware in tight loops it can fill up the autorelease pool, and may be slightly less efficient, but we feel the tradeoffs are acceptable.1234- (void)setFoo:(GMFoo *)aFoo { [_foo autorelease]; // Won't dealloc if |_foo| == |aFoo| _foo = [aFoo retain];} Avoid Accessors During init and deallocInstance subclasses may be in an inconsistent state during init and dealloc method execution, so code in those methods should avoid invoking accessors.Subclasses have not yet been initialized or have already deallocated when init and dealloc methods execute, making accessor methods potentially unreliable. Whenever practical, directly assign to and release ivars in those methods rather than rely on accessors.12345678910111213141516171819202122232425- (instancetype)init { self = [super init]; if (self) { _bar = [[NSMutableString alloc] init]; // good } return self;}- (void)dealloc { [_bar release]; // good [super dealloc];}- (instancetype)init { self = [super init]; if (self) { self.bar = [NSMutableString string]; // avoid } return self;}- (void)dealloc { self.bar = nil; // avoid [super dealloc];} Dealloc Instance Variables in Declaration Orderdealloc should process instance variables in the same order the @interface declares them, so it is easier for a reviewer to verify.A code reviewer checking a new or revised dealloc implementation needs to make sure that every retained instance variable gets released.To simplify reviewing dealloc, order the code so that the retained instance variables get released in the same order that they are declared in the @interface. If dealloc invokes other methods that release instance variables, add comments describing what instance variables those methods handle. Setters copy NSStringsSetters taking an NSString, should always copy the string it accepts.Never just retain the string. This avoids the caller changing it under you without your knowledge. Don’t assume that because you’re accepting an NSString that it’s not actually anNSMutableString.1234- (void)setFoo:(NSString *)aFoo { [_foo autorelease]; _foo = [aFoo copy];} Avoid Throwing ExceptionsDon’t @throw Objective-C exceptions, but you should be prepared to catch them from third-party or OS calls.We do compile with -fobjc-exceptions (mainly so we get @synchronized), but we don’t @throw. Use of @try, @catch, and @finally are allowed when required to properly use 3rd party code or libraries. If you do use them please document exactly which methods you expect to throw. nil ChecksUse nil checks for logic flow only.Use nil pointer checks for logic flow of the application, not for preventing crashes when sending messages. With current compilers ( as of LLVM 3.0/Xcode 4.2), sending a message to nil reliably returns nil as a pointer, zero as an integer or floating-point value, structs initialized to 0, and _Complex values equal to 0, 0.Note that this applies to nil as a message target, not as a parameter value. Individual methods may or may not safely handle nil parameter values.Note too that this is distinct from checking C/C++ pointers and block pointers against NULL, which the runtime does not handle and will cause your application to crash. You still need to make sure you do not dereference a NULL pointer. BOOL PitfallsBe careful when converting general integral values to BOOL. Avoid comparing directly with YES.BOOL is defined as a signed char in Objective-C which means that it can have values other than YES (1) and NO (0). Do not cast or convert general integral values directly to BOOL. Common mistakes include casting or converting an array’s size, a pointer value, or the result of a bitwise logic operation to a BOOL which, depending on the value of the last byte of the integral result, could still result in a NO value. When converting a general integral value to a BOOL use ternary operators to return a YES or NO value.You can safely interchange and convert BOOL, _Bool and bool (see C++ Std 4.7.4, 4.12 and C99 Std 6.3.1.2). You cannot safely interchange BOOL and Boolean so treat Booleans as a general integral value as discussed above. Only use BOOL in Objective C method signatures.Using logical operators (&&, || and !) with BOOL is also valid and will return values that can be safely converted to BOOL without the need for a ternary operator.123456789101112131415161718//avoid- (BOOL)isBold { return [self fontTraits] & NSFontBoldTrait;}- (BOOL)isValid { return [self stringValue];}//good- (BOOL)isBold { return ([self fontTraits] & NSFontBoldTrait) ? YES : NO;}- (BOOL)isValid { return [self stringValue] != nil;}- (BOOL)isEnabled { return [self isValid] && [self isBold];} Also, don’t directly compare BOOL variables directly with YES. Not only is it harder to read for those well-versed in C, the first point above demonstrates that return values may not always be what you expect.123456789//avoidBOOL great = [foo isGreat];if (great == YES) // ...be great!//goodBOOL great = [foo isGreat];if (great) // ...be great! PropertiesUse of the @property directive is preferred, with the following caveat: properties are an Objective-C 2.0 feature which will limit your code to running on the iPhone and Mac OS X 10.5 (Leopard) and higher. Dot notation is allowed only for access to a declared @property. NamingA property’s associated instance variable’s name must conform to the leading _ requirement. The property’s name should be the same as its associated instance variable without the leading _. The optional space between the @property and the opening parenthesis should be omitted, as seen in the examples.12345678@interface MyClass : NSObject@property(copy, nonatomic) NSString *name;@end@implementation MyClass// No code required for auto-synthesis, else use:// @synthesize name = _name;@end LocationA property’s declaration must come immediately after the instance variable block of a class interface. A property’s definition (if not using automatic synthesis) must come immediately after the @implementation block in a class definition. They are indented at the same level as the @interface or @implementation statements that they are enclosed in.1234567891011121314@interface MyClass : NSObject { @private NSString *_name;}@property(copy, nonatomic) NSString *name;@end@implementation MyClass@synthesize name = _name;- (instancetype)init { ...}@end Use Copy Attribute For StringsNSString properties should always be declared with the copy attribute.This logically follows from the requirement that setters for NSStrings always must use copy instead of retain. AtomicityBe aware of the overhead of properties. By default, all synthesized setters and getters are atomic. This gives each set and get calls a substantial amount of synchronization overhead. Declare your properties nonatomic unless you require atomicity. Dot notationDot notation is idiomatic style for Objective-C 2.0. It may be used when doing simple operations to get and set a @property of an object, but should not be used to invoke other object behavior.12345678NSString *oldName = myObject.name;myObject.name = @"Alice";//avoidNSArray *array = [[NSArray arrayWithObject:@"hello"] retain];NSUInteger numberOfItems = array.count; // not a propertyarray.release; // not a property Interfaces Without Instance VariablesOmit the empty set of braces on interfaces that do not declare any instance variables.1234@interface MyClass : NSObject. // Does a lot of stuff - (void)fooBarBam;@end Automatically Synthesized Instance VariablesUse of automatically synthesized instance variables is preferred. Code that must support earlier versions of the compiler toolchain (Xcode 4.3 or earlier or when compiling with GCC) or is using properties inherited from a protocol should prefer the @synthesize directive.123456789101112131415161718// Header file@protocol Thingy@property(nonatomic, copy) NSString *widgetName;@end@interface Foo : NSObject<Thingy>// A guy walks into a bar.@property(nonatomic, copy) NSString *bar;@end// Implementation file@interface Foo ()@property(nonatomic, retain) NSArray *baz;@end@implementation Foo@synthesize widgetName = _widgetName;@end Automatically synthesized instance variables take the form of the property’s name prefixed with an underscore and so typically conform to the required variable naming style. If your property name is unusual, or you are otherwise unable to use automatically synthesized instance variables, use of the @synthesize directive is preferred, with the instance variable name specified explicitly (as @synthesize does not add a leading underscore by default). Automatic Reference Counting (ARC)For projects that use Xcode 4.2 or later and will run only on 64-bit Mac OS X 10.7 and iOS 5.0 and later, ARC is preferred. Use manual reference counting when supporting earlier environments where zeroing weak pointers are not available.Classes that require ARC should include a preprocessor directive to prevent compilation using manual reference counting.Ownership qualifiers like __unsafe_unretained and __weak should precede variable names. Specifying __strong for variables is not required since it is the default. Properties, on the other hand, should always specify the strong keyword rather than relying on the compiler default.Files that are compiled using ARC need to have preprocessor directives to prevent compilation without ARC. See the code snippet below for details.Example of an implementation file enforcing ARC style. Note that declaring instance variables in the @implementation is permitted when using ARC.123456789101112#if !defined(__has_feature) || !__has_feature(objc_arc)#error "This file requires ARC support."#endif#import "Foo.h"@implementation Foo { Bar* __weak _bar; Baz* __unsafe_unretained _baz;}// ...@end NSNumber LiteralsFor projects that use Xcode 4.4 or later with clang, the use of NSNumber literals is allowed. Note however that this will limit the portability of your code to other toolchains.NSNumber literals are used just like Objective C string literals. Boxing is used when necessary. Code using NSNumber literals can be deployed on any iOS/MacOS system.123456NSNumber *fortyTwo = @42;NSNumber *piOverTwo = @(M_PI / 2);enum { kMyEnum = 2;};NSNumber *myEnum = @(kMyEnum); Cocoa PatternsDelegate PatternDelegate objects should not be retained when doing so would create a retain cycle.A class that implements the delegate pattern should typically: Have an instance variable named _delegate to reference the delegate. Thus, the accessor methods should be named delegate and setDelegate:. The _delegate object should be weak if the class is typically retained by its delegate, such that a strong delegate would create a retain cycle.Model/View/ControllerSeparate the model from the view. Separate the controller from the view and the model. Use @protocols for callback APIs. Separate model from view: don’t build assumptions about the presentation into the model or data source. Keep the interface between the data source and the presentation abstract. Don’t give the model knowledge of its view. (A good rule of thumb is to ask yourself if it’s possible to have multiple presentations, with different states, on a single instance of your data source.) Separate controller from view and model: don’t put all of the “business logic” into view-related classes; this makes the code very unusable. Make controller classes to host this code, but ensure that the controller classes don’t make too many assumptions about the presentation. Define callback APIs with @protocol, using @optional if not all the methods are required.Historical NotesTrailing vs Leading UnderscoresTrailing underscores were once preferred for instance variable names.Our style guide used to have a rule saying that instance variables should be named with a trailing underscore, similar to the naming of member variables in C++. This was changed to leading underscores to be consistent with the broader Objective-C community, to better follow Apple’s official guidelines, and to allow for use of new compiler features like automatic instance variable synthesis. New projects are strongly encouraged to use leading underscores. Existing projects may continue to use trailing underscores in new code to maintain consistency with the rest of their codebase.]]></content>
<tags>
<tag>Objective-C</tag>
</tags>
</entry>
<entry>
<title><![CDATA[swift style guide]]></title>
<url>%2F2017%2F04%2F08%2F2017-04-08-swift-style-guide%2F</url>
<content type="text"><![CDATA[This is LinkedIn’s Official Swift Style GuideMake sure to read Apple’s API Design Guidelines.Specifics from these guidelines + additional remarks are mentioned below.This guide was last updated for Swift 3.0 on January 14th, 2017. Code Formatting Use 4 spaces for tabs. Avoid uncomfortably long lines with a hard maximum of 160 characters per line (Xcode->Preferences->Text Editing->Page guide at column: 160 is helpful for this) Ensure that there is a newline at the end of every file. Ensure that there is no trailing whitespace anywhere (Xcode->Preferences->Text Editing->Automatically trim trailing whitespace + Including whitespace-only lines). Do not place opening braces on new lines - we use the 1TBS style. 12345678910111213class SomeClass { func someMethod() { if x == y { /* ... */ } else if x == z { /* ... */ } else { /* ... */ } } /* ... */} When writing a type for a property, constant, variable, a key for a dictionary, a function argument, a protocol conformance, or a superclass, don’t add a space before the colon. 1234567891011121314151617181920212223242526// specifying typelet pirateViewController: PirateViewController// dictionary syntax (note that we left-align as opposed to aligning colons)let ninjaDictionary: [String: AnyObject] = [ "fightLikeDairyFarmer": false, "disgusting": true]// declaring a functionfunc myFunction<T, U: SomeProtocol>(firstArgument: U, secondArgument: T) where T.RelatedType == U { /* ... */}// calling a functionsomeFunction(someArgument: "Kitten")// superclassesclass PirateViewController: UIViewController { /* ... */}// protocolsextension PirateViewController: UITableViewDataSource { /* ... */} In general, there should be a space following a comma. 1let myArray = [1, 2, 3, 4, 5] There should be a space before and after a binary operator such as +, ==, or ->. There should also not be a space after a ( and before a ). 1234567let myValue = 20 + (30 / 2) * 3if 1 + 1 == 3 { fatalError("The universe is broken.")}func pancake(with syrup: Syrup) -> Pancake { /* ... */} We follow Xcode’s recommended indentation style (i.e. your code should not change if CTRL-I is pressed). When declaring a function that spans multiple lines, prefer using that syntax to which Xcode, as of version 7.3, defaults. 123456789101112131415// Xcode indentation for a function declaration that spans multiple linesfunc myFunctionWithManyParameters(parameterOne: String, parameterTwo: String, parameterThree: String) { // Xcode indents to here for this kind of statement print("\(parameterOne) \(parameterTwo) \(parameterThree)")}// Xcode indentation for a multi-line `if` statementif myFirstValue > (mySecondValue + myThirdValue) && myFourthValue == .someEnumValue { // Xcode indents to here for this kind of statement print("Hello, World!")} When calling a function that has many parameters, put each argument on a separate line with a single extra indentation. 1234someFunctionWithManyArguments( firstArgument: "Hello, I am a string", secondArgument: resultFromSomeFunction(), thirdArgument: someOtherLocalProperty) When dealing with an implicit array or dictionary large enough to warrant splitting it into multiple lines, treat the [ and ] as if they were braces in a method, if statement, etc. Closures in a method should be treated similarly. 12345678910111213someFunctionWithABunchOfArguments( someStringArgument: "hello I am a string", someArrayArgument: [ "dadada daaaa daaaa dadada daaaa daaaa dadada daaaa daaaa", "string one is crazy - what is it thinking?" ], someDictionaryArgument: [ "dictionary key 1": "some value 1, but also some more text here", "dictionary key 2": "some value 2" ], someClosure: { parameter1 in print(parameter1) }) Prefer using local constants or other mitigation techniques to avoid multi-line predicates where possible. 1234567891011121314// PREFERREDlet firstCondition = x == firstReallyReallyLongPredicateFunction()let secondCondition = y == secondReallyReallyLongPredicateFunction()let thirdCondition = z == thirdReallyReallyLongPredicateFunction()if firstCondition && secondCondition && thirdCondition { // do something}// NOT PREFERREDif x == firstReallyReallyLongPredicateFunction() && y == secondReallyReallyLongPredicateFunction() && z == thirdReallyReallyLongPredicateFunction() { // do something} Naming There is no need for Objective-C style prefixing in Swift (e.g. use just GuybrushThreepwood instead of LIGuybrushThreepwood). Use PascalCase for type names (e.g. struct, enum, class, typedef, associatedtype, etc.). Use camelCase (initial lowercase letter) for function, method, property, constant, variable, argument names, enum cases, etc.). When dealing with an acronym or other name that is usually written in all caps, actually use all caps in any names that use this in code. The exception is if this word is at the start of a name that needs to start with lowercase - in this case, use all lowercase for the acronym. 12345678// "HTML" is at the start of a constant name, so we use lowercase "html"let htmlBodyContent: String = "<p>Hello, World!</p>"// Prefer using ID to Idlet profileID: Int = 1// Prefer URLFinder to UrlFinderclass URLFinder { /* ... */} All constants other than singletons that are instance-independent should be static. All such static constants should be placed in a container enum type as per rule 3.1.16. The naming of this container should be singular (e.g. Constant and not Constants) and it should be named such that it is relatively obvious that it is a constant container. If this is not obvious, you can add a Constant suffix to the name. You should use these containers to group constants that have similar or the same prefixes, suffixes and/or use cases. 12345678910111213141516171819class MyClassName { // PREFERRED enum AccessibilityIdentifier { static let pirateButton = "pirate_button" } enum SillyMathConstant { static let indianaPi = 3 } static let shared = MyClassName() // NOT PREFERRED static let kPirateButtonAccessibilityIdentifier = "pirate_button" enum SillyMath { static let indianaPi = 3 } enum Singleton { static let shared = MyClassName() }} For generics and associated types, use either a single capital letter or a PascalCase word that describes the generic. If this word clashes with a protocol that it conforms to or a superclass that it subclasses, you can append a Type suffix to the associated type or generic name. 12345678class SomeClass<T> { /* ... */ }class SomeClass<Model> { /* ... */ }protocol Modelable { associatedtype Model}protocol Sequence { associatedtype IteratorType: Iterator} Names should be descriptive and unambiguous. 12345// PREFERREDclass RoundAnimatingButton: UIButton { /* ... */ }// NOT PREFERREDclass CustomButton: UIButton { /* ... */ } Do not abbreviate, use shortened names, or single letter names. 123456789101112131415161718// PREFERREDclass RoundAnimatingButton: UIButton { let animationDuration: NSTimeInterval func startAnimating() { let firstSubview = subviews.first }}// NOT PREFERREDclass RoundAnimating: UIButton { let aniDur: NSTimeInterval func srtAnmating() { let v = subviews.first }} Include type information in constant or variable names when it is not obvious otherwise. 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364// PREFERREDclass ConnectionTableViewCell: UITableViewCell { let personImageView: UIImageView let animationDuration: TimeInterval // it is ok not to include string in the ivar name here because it's obvious // that it's a string from the property name let firstName: String // though not preferred, it is OK to use `Controller` instead of `ViewController` let popupController: UIViewController let popupViewController: UIViewController // when working with a subclass of `UIViewController` such as a table view // controller, collection view controller, split view controller, etc., // fully indicate the type in the name. let popupTableViewController: UITableViewController // when working with outlets, make sure to specify the outlet type in the // property name. @IBOutlet weak var submitButton: UIButton! @IBOutlet weak var emailTextField: UITextField! @IBOutlet weak var nameLabel: UILabel!}// NOT PREFERREDclass ConnectionTableViewCell: UITableViewCell { // this isn't a `UIImage`, so shouldn't be called image // use personImageView instead let personImage: UIImageView // this isn't a `String`, so it should be `textLabel` let text: UILabel // `animation` is not clearly a time interval // use `animationDuration` or `animationTimeInterval` instead let animation: TimeInterval // this is not obviously a `String` // use `transitionText` or `transitionString` instead let transition: String // this is a view controller - not a view let popupView: UIViewController // as mentioned previously, we don't want to use abbreviations, so don't use // `VC` instead of `ViewController` let popupVC: UIViewController // even though this is still technically a `UIViewController`, this property // should indicate that we are working with a *Table* View Controller let popupViewController: UITableViewController // for the sake of consistency, we should put the type name at the end of the // property name and not at the start @IBOutlet weak var btnSubmit: UIButton! @IBOutlet weak var buttonSubmit: UIButton! // we should always have a type in the property name when dealing with outlets // for example, here, we should have `firstNameLabel` instead @IBOutlet weak var firstName: UILabel!} When naming function arguments, make sure that the function can be read easily to understand the purpose of each argument. As per Apple’s API Design Guidelines, a protocol should be named as nouns if they describe what something is doing (e.g. Collection) and using the suffixes able, ible, or ing if it describes a capability (e.g. Equatable, ProgressReporting). If neither of those options makes sense for your use case, you can add a Protocol suffix to the protocol’s name as well. Some example protocols are below.123456789101112131415161718192021// here, the name is a noun that describes what the protocol doesprotocol TableViewSectionProvider { func rowHeight(at row: Int) -> CGFloat var numberOfRows: Int { get } /* ... */}// here, the protocol is a capability, and we name it appropriatelyprotocol Loggable { func logCurrentState() /* ... */}// suppose we have an `InputTextView` class, but we also want a protocol// to generalize some of the functionality - it might be appropriate to// use the `Protocol` suffix hereprotocol InputTextViewProtocol { func sendTrackingEvent() func inputText() -> String /* ... */} Coding StyleGeneral Prefer let to var whenever possible. Prefer the composition of map, filter, reduce, etc. over iterating when transforming from one collection to another. Make sure to avoid using closures that have side effects when using these methods. 123456789101112131415161718192021// PREFERREDlet stringOfInts = [1, 2, 3].flatMap { String($0) }// ["1", "2", "3"]// NOT PREFERREDvar stringOfInts: [String] = []for integer in [1, 2, 3] { stringOfInts.append(String(integer))}// PREFERREDlet evenNumbers = [4, 8, 15, 16, 23, 42].filter { $0 % 2 == 0 }// [4, 8, 16, 42]// NOT PREFERREDvar evenNumbers: [Int] = []for integer in [4, 8, 15, 16, 23, 42] { if integer % 2 == 0 { evenNumbers.append(integer) }} Prefer not declaring types for constants or variables if they can be inferred anyway. If a function returns multiple values, prefer returning a tuple to using inout arguments (it’s best to use labeled tuples for clarity on what you’re returning if it is not otherwise obvious). If you use a certain tuple more than once, consider using a typealias. If you’re returning 3 or more items in a tuple, consider using a struct or class instead. 1234567func pirateName() -> (firstName: String, lastName: String) { return ("Guybrush", "Threepwood")}let name = pirateName()let firstName = name.firstNamelet lastName = name.lastName Be wary of retain cycles when creating delegates/protocols for your classes; typically, these properties should be declared weak. Be careful when calling self directly from an escaping closure as this can cause a retain cycle - use a capture list when this might be the case: 12345678910111213myFunctionWithEscapingClosure() { [weak self] (error) -> Void in // you can do this self?.doSomething() // or you can do this guard let strongSelf = self else { return } strongSelf.doSomething()} Don’t use labeled breaks. Don’t place parentheses around control flow predicates. 123456789// PREFERREDif x == y { /* ... */}// NOT PREFERREDif (x == y) { /* ... */} Avoid writing out an enum type where possible - use shorthand. 12345// PREFERREDimageView.setImageWithURL(url, type: .person)// NOT PREFERREDimageView.setImageWithURL(url, type: AsyncImageView.Type.person) Don’t use shorthand for class methods since it is generally more difficult to infer the context from class methods as opposed to enums. 12345// PREFERREDimageView.backgroundColor = UIColor.white// NOT PREFERREDimageView.backgroundColor = .white Prefer not writing self. unless it is required. When writing methods, keep in mind whether the method is intended to be overridden or not. If not, mark it as final, though keep in mind that this will prevent the method from being overwritten for testing purposes. In general, final methods result in improved compilation times, so it is good to use this when applicable. Be particularly careful, however, when applying the final keyword in a library since it is non-trivial to change something to be non-final in a library as opposed to have changing something to be non-final in your local project. When using a statement such as else, catch, etc. that follows a block, put this keyword on the same line as the block. Again, we are following the 1TBS style here. Example if/else and do/catch code is below. 1234567891011if someBoolean { // do something} else { // do something else}do { let fileContents = try readFile("filename.txt")} catch { print(error)} Prefer static to class when declaring a function or property that is associated with a class as opposed to an instance of that class. Only use class if you specifically need the functionality of overriding that function or property in a subclass, though consider using a protocol to achieve this instead. If you have a function that takes no arguments, has no side effects, and returns some object or value, prefer using a computed property instead. For the purpose of namespacing a set of static functions and/or static properties, prefer using a caseless enum over a class or a struct. This way, you don’t have to add a private init() { } to the container.Access Modifiers Write the access modifier keyword first if it is needed. 12345// PREFERREDprivate static let myPrivateNumber: Int// NOT PREFERREDstatic private let myPrivateNumber: Int The access modifier keyword should not be on a line by itself - keep it inline with what it is describing. 12345678910// PREFERREDopen class Pirate { /* ... */}// NOT PREFERREDopenclass Pirate { /* ... */} In general, do not write the internal access modifier keyword since it is the default. If a property needs to be accessed by unit tests, you will have to make it internal to use @testable import ModuleName. If a property should be private, but you declare it to be internal for the purposes of unit testing, make sure you add an appropriate bit of documentation commenting that explains this. You can make use of the - warning: markup syntax for clarity as shown below. 12345/** This property defines the pirate's name. - warning: Not `private` for `@testable`. */let pirateName = "LeChuck" Prefer private to fileprivate where possible. When choosing between public and open, prefer open if you intend for something to be subclassable outside of a given module and public otherwise. Note that anything internal and above can be subclassed in tests by using @testable import, so this shouldn’t be a reason to use open. In general, lean towards being a bit more liberal with using open when it comes to libraries, but a bit more conservative when it comes to modules in a codebase such as an app where it is easy to change things in multiple modules simultaneously.Custom Operators Prefer creating named functions to custom operators. If you want to introduce a custom operator, make sure that you have a very good reason why you want to introduce a new operator into global scope as opposed to using some other construct. You can override existing operators to support new types (especially ==). However, your new definitions must preserve the semantics of the operator. For example, == must always test equality and return a boolean.Switch Statements and enums When using a switch statement that has a finite set of possibilities (enum), do NOT include a default case. Instead, place unused cases at the bottom and use the break keyword to prevent execution. Since switch cases in Swift break by default, do not include the break keyword if it is not needed. The case statements should line up with the switch statement itself as per default Swift standards. When defining a case that has an associated value, make sure that this value is appropriately labeled as opposed to just types (e.g. case Hunger(hungerLevel: Int) instead of case Hunger(Int)). 12345678910111213141516enum Problem { case attitude case hair case hunger(hungerLevel: Int)}func handleProblem(problem: Problem) { switch problem { case .attitude: print("At least I don't have a hair problem.") case .hair: print("Your barber didn't know when to stop.") case .hunger(let hungerLevel): print("The hunger level is \(hungerLevel).") }} Prefer lists of possibilities (e.g. case 1, 2, 3:) to using the fallthrough keyword where possible). If you have a default case that shouldn’t be reached, preferably throw an error (or handle it some other similar way such as asserting).12345678func handleDigit(_ digit: Int) throws { switch digit { case 0, 1, 2, 3, 4, 5, 6, 7, 8, 9: print("Yes, \(digit) is a digit!") default: throw Error(message: "The given number was not a digit.") }} Optionals The only time you should be using implicitly unwrapped optionals is with @IBOutlets. In every other case, it is better to use a non-optional or regular optional property. Yes, there are cases in which you can probably “guarantee” that the property will never be nil when used, but it is better to be safe and consistent. Similarly, don’t use force unwraps. Don’t use as! or try!. If you don’t plan on actually using the value stored in an optional, but need to determine whether or not this value is nil, explicitly check this value against nil as opposed to using if let syntax. 123456789// PREFEREREDif someOptional != nil { // do something}// NOT PREFERREDif let _ = someOptional { // do something} Don’t use unowned. You can think of unowned as somewhat of an equivalent of a weak property that is implicitly unwrapped (though unowned has slight performance improvements on account of completely ignoring reference counting). Since we don’t ever want to have implicit unwraps, we similarly don’t want unowned properties. 123456// PREFERREDweak var parentViewController: UIViewController?// NOT PREFERREDweak var parentViewController: UIViewController!unowned var parentViewController: UIViewController When unwrapping optionals, use the same name for the unwrapped constant or variable where appropriate. 123guard let myValue = myValue else { return} Protocols When implementing protocols, there are two ways of organizing your code: Using // MARK: comments to separate your protocol implementation from the rest of your code Using an extension outside your class/struct implementation code, but in the same source file Keep in mind that when using an extension, however, the methods in the extension can’t be overridden by a subclass, which can make testing difficult. If this is a common use case, it might be better to stick with method #1 for consistency. Otherwise, method #2 allows for cleaner separation of concerns. Even when using method #2, add // MARK: statements anyway for easier readability in Xcode’s method/property/class/etc. list UI.Properties If making a read-only, computed property, provide the getter without the get {} around it. 123456var computedProperty: String { if someBool { return "I'm a mighty pirate!" } return "I'm selling these fine leather jackets."} When using get {}, set {}, willSet, and didSet, indent these blocks. Though you can create a custom name for the new or old value for willSet/didSet and set, use the standard newValue/oldValue identifiers that are provided by default. 1234567891011121314151617181920var storedProperty: String = "I'm selling these fine leather jackets." { willSet { print("will set to \(newValue)") } didSet { print("did set from \(oldValue) to \(storedProperty)") }}var computedProperty: String { get { if someBool { return "I'm a mighty pirate!" } return storedProperty } set { storedProperty = newValue }} You can declare a singleton property as follows: 12345class PirateManager { static let shared = PirateManager() /* ... */} Closures If the types of the parameters are obvious, it is OK to omit the type name, but being explicit is also OK. Sometimes readability is enhanced by adding clarifying detail and sometimes by taking repetitive parts away - use your best judgment and be consistent. 123456789101112// omitting the typedoSomethingWithClosure() { response in print(response)}// explicit typedoSomethingWithClosure() { response: NSURLResponse in print(response)}// using shorthand in a map statement[1, 2, 3].flatMap { String($0) } If specifying a closure as a type, you don’t need to wrap it in parentheses unless it is required (e.g. if the type is optional or the closure is within another closure). Always wrap the arguments in the closure in a set of parentheses - use () to indicate no arguments and use Void to indicate that nothing is returned. 123456789let completionBlock: (Bool) -> Void = { (success) in print("Success? \(success)")}let completionBlock: () -> Void = { print("Completed!")}let completionBlock: (() -> Void)? = nil Keep parameter names on same line as the opening brace for closures when possible without too much horizontal overflow (i.e. ensure lines are less than 160 characters). Use trailing closure syntax unless the meaning of the closure is not obvious without the parameter name (an example of this could be if a method has parameters for success and failure closures).1234567891011// trailing closuredoSomething(1.0) { (parameter1) in print("Parameter 1 is \(parameter1)")}// no trailing closuredoSomething(1.0, success: { (parameter1) in print("Success with \(parameter1)")}, failure: { (parameter1) in print("Failure with \(parameter1)")}) Arrays In general, avoid accessing an array directly with subscripts. When possible, use accessors such as .first or .last, which are optional and won’t crash. Prefer using a for item in items syntax when possible as opposed to something like for i in 0 ..< items.count. If you need to access an array subscript directly, make sure to do proper bounds checking. You can use for (index, value) in items.enumerated() to get both the index and the value. Never use the += or + operator to append/concatenate to arrays. Instead, use .append() or .append(contentsOf:) as these are far more performant (at least with respect to compilation) in Swift’s current state. If you are declaring an array that is based on other arrays and want to keep it immutable, instead of let myNewArray = arr1 + arr2, use let myNewArray = [arr1, arr2].flatten().Error Handling Suppose a function myFunction is supposed to return a String, however, at some point it can run into an error. A common approach is to have this function return an optional String? where we return nil if something went wrong. Example: 123456789101112131415161718func readFile(named filename: String) -> String? { guard let file = openFile(named: filename) else { return nil } let fileContents = file.read() file.close() return fileContents}func printSomeFile() { let filename = "somefile.txt" guard let fileContents = readFile(named: filename) else { print("Unable to open file \(filename).") return } print(fileContents)} Instead, we should be using Swift’s try/catch behavior when it is appropriate to know the reason for the failure. You can use a struct such as the following: 12345678910111213struct Error: Swift.Error { public let file: StaticString public let function: StaticString public let line: UInt public let message: String public init(message: String, file: StaticString = #file, function: StaticString = #function, line: UInt = #line) { self.file = file self.function = function self.line = line self.message = message }} Example usage: 123456789101112131415161718func readFile(named filename: String) throws -> String { guard let file = openFile(named: filename) else { throw Error(message: "Unable to open file named \(filename).") } let fileContents = file.read() file.close() return fileContents}func printSomeFile() { do { let fileContents = try readFile(named: filename) print(fileContents) } catch { print(error) }} There are some exceptions in which it does make sense to use an optional as opposed to error handling. When the result should semantically potentially be nil as opposed to something going wrong while retrieving the result, it makes sense to return an optional instead of using error handling. In general, if a method can “fail”, and the reason for the failure is not immediately obvious if using an optional return type, it probably makes sense for the method to throw an error.Using guard Statements In general, we prefer to use an “early return” strategy where applicable as opposed to nesting code in if statements. Using guard statements for this use-case is often helpful and can improve the readability of the code. 123456789101112131415161718// PREFERREDfunc eatDoughnut(at index: Int) { guard index >= 0 && index < doughnuts.count else { // return early because the index is out of bounds return } let doughnut = doughnuts[index] eat(doughnut)}// NOT PREFERREDfunc eatDoughnut(at index: Int) { if index >= 0 && index < doughnuts.count { let doughnut = doughnuts[index] eat(doughnut) }} When unwrapping optionals, prefer guard statements as opposed to if statements to decrease the amount of nested indentation in your code. 12345678910111213141516171819// PREFERREDguard let monkeyIsland = monkeyIsland else { return}bookVacation(on: monkeyIsland)bragAboutVacation(at: monkeyIsland)// NOT PREFERREDif let monkeyIsland = monkeyIsland { bookVacation(on: monkeyIsland) bragAboutVacation(at: monkeyIsland)}// EVEN LESS PREFERREDif monkeyIsland == nil { return}bookVacation(on: monkeyIsland!)bragAboutVacation(at: monkeyIsland!) When deciding between using an if statement or a guard statement when unwrapping optionals is not involved, the most important thing to keep in mind is the readability of the code. There are many possible cases here, such as depending on two different booleans, a complicated logical statement involving multiple comparisons, etc., so in general, use your best judgement to write code that is readable and consistent. If you are unsure whether guard or if is more readable or they seem equally readable, prefer using guard. 1234567891011121314// an `if` statement is readable hereif operationFailed { return}// a `guard` statement is readable hereguard isSuccessful else { return}// double negative logic like this can get hard to read - i.e. don't do thisguard !operationFailed else { return} If choosing between two different states, it makes more sense to use an if statement as opposed to a guard statement. 1234567891011121314// PREFERREDif isFriendly { print("Hello, nice to meet you!")} else { print("You have the manners of a beggar.")}// NOT PREFERREDguard isFriendly else { print("You have the manners of a beggar.") return}print("Hello, nice to meet you!") You should also use guard only if a failure should result in exiting the current context. Below is an example in which it makes more sense to use two if statements instead of using two guards - we have two unrelated conditions that should not block one another. 1234567if let monkeyIsland = monkeyIsland { bookVacation(onIsland: monkeyIsland)}if let woodchuck = woodchuck, canChuckWood(woodchuck) { woodchuck.chuckWood()} Often, we can run into a situation in which we need to unwrap multiple optionals using guard statements. In general, combine unwraps into a single guard statement if handling the failure of each unwrap is identical (e.g. just a return, break, continue, throw, or some other @noescape). 12345678910111213141516171819// combined because we just returnguard let thingOne = thingOne, let thingTwo = thingTwo, let thingThree = thingThree else { return}// separate statements because we handle a specific error in each caseguard let thingOne = thingOne else { throw Error(message: "Unwrapping thingOne failed.")}guard let thingTwo = thingTwo else { throw Error(message: "Unwrapping thingTwo failed.")}guard let thingThree = thingThree else { throw Error(message: "Unwrapping thingThree failed.")} Don’t use one-liners for guard statements. 1234567// PREFERREDguard let thingOne = thingOne else { return}// NOT PREFERREDguard let thingOne = thingOne else { return } Documentation/CommentsDocumentationIf a function is more complicated than a simple O(1) operation, you should generally consider adding a doc comment for the function since there could be some information that the method signature does not make immediately obvious. If there are any quirks to the way that something was implemented, whether technically interesting, tricky, not obvious, etc., this should be documented. Documentation should be added for complex classes/structs/enums/protocols and properties. All public functions/classes/properties/constants/structs/enums/protocols/etc. should be documented as well (provided, again, that their signature/name does not make their meaning/functionality immediately obvious).After writing a doc comment, you should option click the function/property/class/etc. to make sure that everything is formatted correctly.Be sure to check out the full set of features available in Swift’s comment markup described in Apple’s Documentation.Guidelines: 160 character column limit (like the rest of the code). Even if the doc comment takes up one line, use block (/** */). Do not prefix each additional line with a *. Use the new - parameter syntax as opposed to the old :param: syntax (make sure to use lower case parameter and not Parameter). See the documentation on Swift Markup for more details on how this is formatted. If you’re going to be documenting the parameters/returns/throws of a method, document all of them, even if some of the documentation ends up being somewhat repetitive (this is preferable to having the documentation look incomplete). Sometimes, if only a single parameter warrants documentation, it might be better to just mention it in the description instead. For complicated classes, describe the usage of the class with some potential examples as seems appropriate. Remember that markdown syntax is valid in Swift’s comment docs. Newlines, lists, etc. are therefore appropriate. 12345678910111213141516171819202122232425262728/** ## Feature Support This class does some awesome things. It supports: - Feature 1 - Feature 2 - Feature 3 ## Examples Here is an example use case indented by four spaces because that indicates a code block: let myAwesomeThing = MyAwesomeClass() myAwesomeThing.makeMoney() ## Warnings There are some things you should be careful of: 1. Thing one 2. Thing two 3. Thing three */class MyAwesomeClass { /* ... */} When mentioning code, use code ticks - ` 1234567/** This does something with a `UIViewController`, perchance. - warning: Make sure that `someValue` is `true` before running this function. */func myFunction() { /* ... */} When writing doc comments, prefer brevity where possible. Other Commenting Guidelines Always leave a space after //. Always leave comments on their own line. When using // MARK: - whatever, leave a newline after the comment.12345678910111213class Pirate { // MARK: - instance properties private let pirateName: String // MARK: - initialization init() { /* ... */ }}]]></content>
<tags>
<tag>Swift</tag>
</tags>
</entry>
</search>