├── README.md ├── content ├── a-skill-one-line.md ├── all-devices.md ├── always-pass-weak-reference-of-self-into-block-in-arc.md ├── any-way-to-bold-part-of-a-nsstring.md ├── applicationwillenterforeground-vs-applicationdidbecomeactive-applicationwillre.md ├── best-way-to-remove-from-nsmutablearray-while-iterating.md ├── best-way-to-sort-an-nsarray-of-nsdictionary-objects.md ├── can-i-embed-a-custom-font-in-an-iphone-application.md ├── can-you-animate-a-height-change-on-a-uitableviewcell-when-selected.md ├── cancelling-queued-performselectorafterdelay-calls.md ├── catch-exception.md ├── check-if-ios-app-is-in-background.md ├── checking-a-null-value-in-objective-c-that-has-been-returned-from-a-json-string.md ├── class-vs-import.md ├── constants-in-objective-c.md ├── creating-a-blurring-overlay-view.md ├── deep-copying-an-nsarray.md ├── detect-if-the-device-is-iphone-x.md ├── detecting-taps-on-attributed-text-in-a-uitextview-in-ios.md ├── detecting-when-the-back-button-is-pressed-on-a-navbar.md ├── difference-between-nil-nil-and-null-in-objective-c.md ├── difference-between-objectforkey-and-valueforkey.md ├── dispatch-sync-always-scheduling-a-block-on-main-thread.md ├── does-the-apns-device-token-ever-change-once-created.md ├── draw-color-export-image.md ├── duplicate-simulators.md ├── easy-way-to-see-saved-nsuserdefaults.md ├── filtering-nsarray-into-a-new-nsarray-in-objective-c.md ├── get-parts-of-a-nsurl-in-objective-c.md ├── how-can-i-create-a-uicolor-from-a-hex-string.md ├── how-can-i-programmatically-get-the-mac-address-of-an-iphone.md ├── how-disable-copy-cut-select-select-all-in-uitextview.md ├── how-do-i-animate-constraint-changes.md ├── how-do-i-check-if-a-string-contains-another-string-in-objective-c.md ├── how-do-i-detect-when-someone-shakes-an-iphone.md ├── how-do-i-sort-an-nsmutablearray-with-custom-objects-in-it.md ├── how-does-synchronized-lock-unlock-in-objective-c.md ├── how-to-add-a-border-just-on-the-top-side-of-a-uiview.md ├── how-to-check-for-an-active-internet-connection-on-ios-or-osx.md ├── how-to-check-if-an-nsdate-occurs-between-two-other-nsdates.md ├── how-to-compare-uicolors.md ├── how-to-create-an-array-of-selectors.md ├── how-to-embed-small-icon-in-uilabel.md ├── how-to-fill-background-image-of-an-uiview.md ├── how-to-get-uitableview-from-uitableviewcell.md ├── how-to-hide-uinavigationbar-1px-bottom-line.md ├── how-to-pass-object-with-nsnotificationcenter.md ├── how-to-rotate-a-uiimage-90-degrees.md ├── how-to-scale-a-uiimageview-proportionally.md ├── how-to-set-the-full-width-of-separator-in-uitableview.md ├── how-to-stop-unwanted-uibutton-animation-on-title-change.md ├── how-to-store-custom-objects-in-nsuserdefaults.md ├── how-to-swizzle-a-class-method-on-ios.md ├── how-to-tell-if-uiviewcontrollers-view-is-visible.md ├── how-to-use-nscache.md ├── ios-app-programmatically-get-build-version.md ├── iphone-sdk-what-is-the-difference-between-loadview-and-viewdidload.md ├── is-autoreleasepool-still-required-for-modern-ios-8-nsoperation-usage.md ├── make-autolayout.md ├── nsobject-load-and-initialize-what-do-they-do.md ├── nsoperation-vs-grand-central-dispatch.md ├── nsstring-property-copy-or-retain.md ├── number-of-days-between-two-nsdates.md ├── objective-c-assertion-vs-exception-vs-error.md ├── objective-c-declared-property-attributes-nonatomic-copy-strong-weak.md ├── objective-c-pass-block-as-parameter.md ├── push-viewcontroller-slow.md ├── send-post-request-using-nsurlsession.md ├── some-questions.md ├── synthesize-vs-dynamic-what-are-the-differences.md ├── the-best-way-to-remove-duplicate-values-from-nsmutablearray-in-objective-c.md ├── try-catch-block-in-objective-c.md ├── types-in-objective-c-on-iphone.md ├── uialertcontroller-custom-font-size-color.md ├── uibutton-how-to-center-an-image-and-a-text-using-imageedgeinsets-and-titleedgei.md ├── uiview-frame-bounds-and-center.md ├── using-a-constant-nsstring-as-the-key-for-nsuserdefaults.md ├── using-objc-setassociatedobject-with-weak-references.md ├── using-performselector-vs-just-calling-the-method.md ├── vertically-align-text-to-top-within-a-uilabel.md ├── what-are-the-dangers-of-method-swizzling-in-objective-c.md ├── what-does-private-mean-in-objective-c.md ├── what-is-nszombie.md ├── what-is-the-best-way-to-create-constants-in-objective-c.md ├── what-is-the-difference-between-ivars-and-properties-in-objective-c.md ├── what-is-the-difference-between-releasing-and-autoreleasing.md ├── what-is-the-meaning-of-id.md ├── whats-the-best-way-to-put-a-c-struct-in-an-nsarray.md ├── whats-the-difference-between-a-method-and-a-selector.md ├── whats-the-difference-between-the-atomic-and-nonatomic-attributes.md ├── when-is-it-better-to-use-an-nsset-over-an-nsarray.md ├── when-to-use-enumerateobjectsusingblock-vs-for.md ├── when-to-use-nsinteger-vs-int.md └── zz.md └── images ├── 01.png ├── 02.png ├── 03.png ├── 04.jpg ├── 05.png ├── 06.jpg ├── 07.png ├── 08.png ├── 09.png ├── 10.png ├── 11.png ├── 12.png ├── 13.png ├── 14.png ├── 15.png └── 16.png /README.md: -------------------------------------------------------------------------------- 1 | # stackoverflow_top_ios 2 | ![img](/images/14.png) 3 | stackoverflow上Votes数排名靠前的部分问题整理 4 | 5 | 1. [一行代码了事](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/a-skill-one-line.md) 6 | 2. [iOS设备的尺寸和分辨率](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/all-devices.md) 7 | 3. [atomic和nonatomic有什么区别?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/whats-the-difference-between-the-atomic-and-nonatomic-attributes.md) 8 | 4. [UILabel的文字如何垂直居上?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/vertically-align-text-to-top-within-a-uilabel.md) 9 | 5. [使用Method-swizzling的危害?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/what-are-the-dangers-of-method-swizzling-in-objective-c.md) 10 | 6. [如何判断iOS或者OSX的网络连接状况?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-to-check-for-an-active-internet-connection-on-ios-or-osx.md) 11 | 7. [如何判断一个字符串包含另外一个字符串?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-do-i-check-if-a-string-contains-another-string-in-objective-c.md) 12 | 8. [如何在NSMutableArray里对自定义对象进行排序?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-do-i-sort-an-nsmutablearray-with-custom-objects-in-it.md) 13 | 9. [如何声明一个全局常量?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/constants-in-objective-c.md) 14 | 10. [@class VS #import](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/class-vs-import.md) 15 | 11. [@synthesize vs @dynamic](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/synthesize-vs-dynamic-what-are-the-differences.md) 16 | 12. [NSobject的+load +initialize分别做了什么?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/nsobject-load-and-initialize-what-do-they-do.md) 17 | 13. [UIImageView的伸缩模式](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-to-scale-a-uiimageview-proportionally.md) 18 | 14. [objectForKey和valueForKey有什么区别?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/difference-between-objectforkey-and-valueforkey.md) 19 | 15. [NSString的属性修饰符应该用copy还是strong(retain)?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/nsstring-property-copy-or-retain.md) 20 | 16. [什么情况下使用NSInteger或者Int?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/when-to-use-nsinteger-vs-int.md) 21 | 17. [UIView的frame, bounds, center?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/uiview-frame-bounds-and-center.md) 22 | 18. [@private在Objective-C里是什么意思?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/what-does-private-mean-in-objective-c.md) 23 | 19. [Objective-C属性修饰符(nonatomic, copy, strong, weak)?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/objective-c-declared-property-attributes-nonatomic-copy-strong-weak.md) 24 | 20. [如何在NSUserDefaults里保存一个自定义对象?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-to-store-custom-objects-in-nsuserdefaults.md) 25 | 21. [更改布局时如何用动画?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-do-i-animate-constraint-changes.md) 26 | 22. [APP里如何使用自定义字体?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/can-i-embed-a-custom-font-in-an-iphone-application.md) 27 | 23. [NSOperation vs. GCD?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/nsoperation-vs-grand-central-dispatch.md) 28 | 24. [自动布局](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/make-autolayout.md) 29 | 25. [选中UITableViewCell时动画更改高度](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/can-you-animate-a-height-change-on-a-uitableviewcell-when-selected.md) 30 | 26. [如何隐藏UINavigationBar底部的线?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-to-hide-uinavigationbar-1px-bottom-line.md) 31 | 27. [创建一个带模糊效果的View](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/creating-a-blurring-overlay-view.md) 32 | 28. [用NSURLSession发送一个POST请求](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/send-post-request-using-nsurlsession.md) 33 | 29. [往ARC的Block传值一定要弱引用么](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/always-pass-weak-reference-of-self-into-block-in-arc.md) 34 | 30. [NSMutableArray遍历移除的最好方式?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/best-way-to-remove-from-nsmutablearray-while-iterating.md) 35 | 31. [查看存储在NSUserDefaults的值](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/easy-way-to-see-saved-nsuserdefaults.md) 36 | 32. [@synchronized是如何加锁/解锁?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-does-synchronized-lock-unlock-in-objective-c.md) 37 | 33. [nil, NIL, NULL, NSNull的区别?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/difference-between-nil-nil-and-null-in-objective-c.md) 38 | 34. [application几种状态](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/applicationwillenterforeground-vs-applicationdidbecomeactive-applicationwillre.md) 39 | 35. [@try - catch block](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/try-catch-block-in-objective-c.md) 40 | 36. [旋转图片](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-to-rotate-a-uiimage-90-degrees.md) 41 | 37. [背景图片充满UIView?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-to-fill-background-image-of-an-uiview.md) 42 | 38. [Objective-C声明常量的最好方式](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/what-is-the-best-way-to-create-constants-in-objective-c.md) 43 | 39. [Objective-C里类型大小](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/types-in-objective-c-on-iphone.md) 44 | 40. [检测iOS APP是否在后台](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/check-if-ios-app-is-in-background.md) 45 | 41. [去除UIButton修改标题时的动画效果](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-to-stop-unwanted-uibutton-animation-on-title-change.md) 46 | 42. [如何使UIButton的图片和文字都居中?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/uibutton-how-to-center-an-image-and-a-text-using-imageedgeinsets-and-titleedgei.md) 47 | 43. [计算两个NSDate之间的天数?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/number-of-days-between-two-nsdates.md) 48 | 44. [for循环 vs. enumerateObjectsUsingBlock](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/when-to-use-enumerateobjectsusingblock-vs-for.md) 49 | 45. [设备唯一标识/MAC地址](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-can-i-programmatically-get-the-mac-address-of-an-iphone.md) 50 | 46. [数组去重](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/the-best-way-to-remove-duplicate-values-from-nsmutablearray-in-objective-c.md) 51 | 47. [loadView和viewDidLoad](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/iphone-sdk-what-is-the-difference-between-loadview-and-viewdidload.md) 52 | 48. [Block作为参数传递](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/objective-c-pass-block-as-parameter.md) 53 | 49. [UIColor进行比较](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-to-compare-uicolors.md) 54 | 50. [如何使用NSCache?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-to-use-nscache.md) 55 | 51. [NSArray的深拷贝](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/deep-copying-an-nsarray.md) 56 | 52. [UITableView填满分割线](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-to-set-the-full-width-of-separator-in-uitableview.md) 57 | 53. [performSelector: vs. method](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/using-performselector-vs-just-calling-the-method.md) 58 | 54. [取消performSelector:afterDelay](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/cancelling-queued-performselectorafterdelay-calls.md) 59 | 55. [获取NSURL里的部分信息](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/get-parts-of-a-nsurl-in-objective-c.md) 60 | 56. [获取APP的版本信息](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/ios-app-programmatically-get-build-version.md) 61 | 57. [NSNotificationCenter传递对象](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-to-pass-object-with-nsnotificationcenter.md) 62 | 58. [NSSet vs. NSArray](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/when-is-it-better-to-use-an-nsset-over-an-nsarray.md) 63 | 59. [UILabel嵌入小图片](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-to-embed-small-icon-in-uilabel.md) 64 | 60. [16进制的UIColor](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-can-i-create-a-uicolor-from-a-hex-string.md) 65 | 61. [如何判断UIViewController的View是否可见](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-to-tell-if-uiviewcontrollers-view-is-visible.md) 66 | 62. [如何检测手机的摇动?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-do-i-detect-when-someone-shakes-an-iphone.md) 67 | 63. [数组过滤](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/filtering-nsarray-into-a-new-nsarray-in-objective-c.md) 68 | 64. [给UIView的一边添加border](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-to-add-a-border-just-on-the-top-side-of-a-uiview.md) 69 | 65. [判断设备型号iphone X](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/detect-if-the-device-is-iphone-x.md) 70 | 66. [检测UITextView上的点击了字符串](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/detecting-taps-on-attributed-text-in-a-uitextview-in-ios.md) 71 | 67. [监测NavBar的返回按钮被点击](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/detecting-when-the-back-button-is-pressed-on-a-navbar.md) 72 | 68. [禁用UITextView的粘贴板功能](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-disable-copy-cut-select-select-all-in-uitextview.md) 73 | 69. [判断一个时间在另外两个时间之间](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-to-check-if-an-nsdate-occurs-between-two-other-nsdates.md) 74 | 70. [什么是僵尸对象?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/what-is-nszombie.md) 75 | 71. [APNs的Token创建后会更新吗?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/does-the-apns-device-token-ever-change-once-created.md) 76 | 72. [创建一个Selectors的数组](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-to-create-an-array-of-selectors.md) 77 | 73. [数组存储结构体](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/whats-the-best-way-to-put-a-c-struct-in-an-nsarray.md) 78 | 74. [实例变量(iVar)与属性(property)的区别](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/what-is-the-difference-between-ivars-and-properties-in-objective-c.md) 79 | 75. [Method vs. selector vs. IMP](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/whats-the-difference-between-a-method-and-a-selector.md) 80 | 76. [JSON字符串里的null处理](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/checking-a-null-value-in-objective-c-that-has-been-returned-from-a-json-string.md) 81 | 77. [Objective-C: Assertion vs. Exception vs. Error](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/objective-c-assertion-vs-exception-vs-error.md) 82 | 78. [字符串常量作为key](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/using-a-constant-nsstring-as-the-key-for-nsuserdefaults.md) 83 | 79. [UIAlertController自定义字体](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/uialertcontroller-custom-font-size-color.md) 84 | 80. [获取UITableViewCell的UITableView](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-to-get-uitableview-from-uitableviewcell.md) 85 | 81. [字符串部分粗体](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/any-way-to-bold-part-of-a-nsstring.md) 86 | 82. [画图并导出沙盒](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/draw-color-export-image.md) 87 | 83. [捕获异常](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/catch-exception.md) 88 | 84. [NSOperation或者GCD编程是否需要autoreleasepool?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/is-autoreleasepool-still-required-for-modern-ios-8-nsoperation-usage.md) 89 | 85. [Dispatch_sync](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/dispatch-sync-always-scheduling-a-block-on-main-thread.md) 90 | 86. [autorelease和release有什么区别?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/what-is-the-difference-between-releasing-and-autoreleasing.md) 91 | 87. [Swizzle 类方法](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/how-to-swizzle-a-class-method-on-ios.md) 92 | 88. [如何objc_setAssociatedObject关联weak属性](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/using-objc-setassociatedobject-with-weak-references.md) 93 | 89. [几道题目](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/some-questions.md) 94 | 90. [id类型](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/what-is-the-meaning-of-id.md) 95 | 91. [Xcode重复出现多个模拟器的处理方法](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/duplicate-simulators.md) 96 | 92. [字典数组的排序?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/best-way-to-sort-an-nsarray-of-nsdictionary-objects.md) 97 | 93. [UINavigationController在pushViewController时卡顿?](https://github.com/helloted/stackoverflow_top_ios/blob/master/content/push-viewcontroller-slow.md) 98 | 99 | 100 | -------------------------------------------------------------------------------- /content/a-skill-one-line.md: -------------------------------------------------------------------------------- 1 | # 一行代码了事 2 | ___ 3 | 4 | 1、当前选中的UITableView Index: 5 | 6 | ```objc 7 | NSIndexPath *selectedIndexPath = [tableView indexPathForSelectedRow]; 8 | ``` 9 | 10 | 2、检测当前键盘是否弹出? 11 | 12 | ``` 13 | BOOL isFisrt = [myTextField isFirstResponder] 14 | ``` 15 | 16 | 3、移除字符串空格 17 | 18 | ``` 19 | NSString *stringWithoutSpaces = [myString stringByReplacingOccurrencesOfString:@" " withString:@""]; 20 | ``` 21 | 22 | 4、最顶层加一个View 23 | 24 | ``` 25 | [[[UIApplication sharedApplication] keyWindow] addSubview:someView] 26 | ``` 27 | 28 | 5、字典拼接 29 | 30 | ``` 31 | [NSMutableDictionary addEntriesFromDictionary:otherDict] 32 | ``` 33 | 34 | 6、获取毫秒时间戳 35 | 36 | ``` 37 | CFAbsoluteTime timeInSeconds = CFAbsoluteTimeGetCurrent(); 38 | ``` 39 | 40 | 7、模拟器沙盒路径 41 | 42 | ``` 43 | po NSHomeDirectory(); 44 | ``` 45 | 46 | 8、旋转 47 | 48 | ```c++ 49 | [myView setTransform:CGAffineTransformMakeRotation(-M_PI / 2)]; 50 | ``` 51 | 52 | 9、KVO的keypath 53 | 54 | ``` 55 | #define KVOKeyPath(PATH) @(((void)(NO && ((void)PATH, NO)), strchr(# PATH, '.') + 1)) 56 | ``` 57 | 58 | (void)是为了防止逗号表达式的warning。加NO是为了C短路判断条件表达式。编译器看见了NO && 以后,就会很快的跳过之后的判断条件。 59 | 60 | 在宏中,#代表把宏的参数名转化为一个字符串。而strchr函数使用来查找字符串s中首次出现字符c的位置。返回首次出现字符c的位置的指针,返回的地址是被查找字符串指针开始的第一个与字符c相同字符的指针,如果字符串中不存在字符c则返回NULL。 61 | 62 | 最后我们通过strchr函数得到了一个C的字符串,通过@( )包起来,就变成了一个OC的字符串了。 63 | 64 | 10、防止subView的透明度受到影响 65 | 66 | 当给一个View设置Alpha时,所有的subView的透明度也跟着被设置,所以应该设置opacity 67 | 68 | ``` 69 | view.layer.opacity = 0.85; 70 | ``` 71 | 72 | 11、相对位置 73 | 74 | ``` 75 | [viewB convertRect:viewC.frame toView:viewA]; 76 | 计算viewB上的viewC相对于viewA的frame。 77 | 78 | [viewC convertRect:viewB.frame fromView:viewA]; 79 | 计算viewA上的viewB相对于viewC的frame。 80 | ``` 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /content/all-devices.md: -------------------------------------------------------------------------------- 1 | # iOS设备的尺寸和分辨率? 2 | ___ 3 | 4 | 5 | 6 | > 1 7 | 8 | #### iPhone 9 | 10 | | 设备 | 像素分辨率(px) | 倍数 | 点分辨率(pt) | 屏幕分辨率 | 屏幕尺寸 | ppi | 11 | | ----------------------------------- | -------------- | ---- | ------------ | ---------- | -------- | ---- | 12 | | iPhone/3G/3GS | 480*320 | @1x | 480*320 | 480*320 | 3.5 | 163 | 13 | | iPhone 4/4s | 960*640 | @2x | 480*320 | 960*640 | 3.5 | 326 | 14 | | iPhone 5/5s/5c/SE | 1136*640 | @2x | 568*320 | 1136*640 | 4.0 | 326 | 15 | | iPhone 6/6s/7/8 | 1334*750 | @2x | 667*375 | 1334*750 | 4.7 | 326 | 16 | | iPhone 6 plus/6s plus/7 plus/8 plus | 2208*1242 | @3x | 736*414 | 1920*1080 | 5.5 | 401 | 17 | | iPhone X/XS | 2436*1125 | @3x | 812*375 | 2436*1125 | 5.8 | 458 | 18 | | iPhone XR | 1792*828 | @2x | 896*414 | 1792*828 | 6.1 | 326 | 19 | | Iphone XS max | 2688*1242 | @3x | 896*414 | 2688*1242 | 6.5 | 458 | 20 | 21 | 22 | 23 | #### iPad 24 | 25 | | 设备 | 像素分辨率(px) | 倍数 | 点分辨率(pt) | 屏幕尺寸 | ppi | 26 | | ----------------- | -------------- | ---- | ------------ | -------- | ---- | 27 | | iPad 1/2 | 1024*768 | @1x | 1024*768 | 9.7 | 132 | 28 | | iPad mini | 1024*768 | @1x | 1024*768 | 7.9 | 163 | 29 | | iPad 3/4/Air/Air2 | 2048*1536 | @2x | 1024*768 | 9.7 | 264 | 30 | | iPad mini 3/4 | 2048*1536 | @2x | 1024*768 | 7.9 | 326 | 31 | | iPad Pro 10.5 | 2224*1668 | @2x | 1112*834 | 10.5 | 264 | 32 | | iPad Pro 12.9 | 2732*2048 | @2x | 1366*1024 | 12.9 | 264 | 33 | 34 | #### -------------------------------------------------------------------------------- /content/always-pass-weak-reference-of-self-into-block-in-arc.md: -------------------------------------------------------------------------------- 1 | # 往ARC的Block传值一定要弱引用么? 2 | [Always pass weak reference of self into block in ARC?](https://stackoverflow.com/questions/20030873/always-pass-weak-reference-of-self-into-block-in-arc) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 一个循环引用产生时因为当A对象retains对象B,并且对象B retains 对象A,在这种情况下,如果其中一个对象被released: 11 | 12 | - 对象A不会被dealloc因为对象B强引用了它 13 | - 但是对象B也不会被dealloc同样因为对象A引用了它 14 | - 但是对象A不会被dealloc因为对象B强引用了它 15 | - …... 16 | 17 | 这样的话,这两个对象就会一直在内存中尽管它们“应该”被回收掉。 18 | 19 | 所以,我们要担心的是循环引用而不是block,像下面这种情况不会产生循环就没有问题: 20 | 21 | ```objc 22 | [myArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){ 23 | [self doSomethingWithObject:obj]; 24 | }]; 25 | ``` 26 | 27 | Block retain了self,但是self并没有引用block,如果其中一个被释放了,不会有循环引用产生而且所有的对象都会及时得到释放 28 | 29 | 下面这种情况就会有问题: 30 | 31 | ```objc 32 | //In the interface: 33 | @property (strong) void(^myBlock)(id obj, NSUInteger idx, BOOL *stop); 34 | 35 | //In the implementation: 36 | [self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) { 37 | [self doSomethingWithObj:obj]; 38 | }]; 39 | ``` 40 | 41 | 现在,self对block有一个强引用,而且block对self也有一个强引用,这样就产生了一个循环。。解决这个问题也很简单,将block对self的引用改为弱引用: 42 | 43 | ```objc 44 | __weak MyObject *weakSelf = self; 45 | [self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) { 46 | [weakSelf doSomethingWithObj:obj]; 47 | }]; 48 | ``` 49 | 50 | -------------------------------------------------------------------------------- /content/any-way-to-bold-part-of-a-nsstring.md: -------------------------------------------------------------------------------- 1 | # 字符串部分粗体 2 | [Any way to bold part of a NSString?](https://stackoverflow.com/questions/6013705/any-way-to-bold-part-of-a-nsstring) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 用NSMutableAttributedString 11 | 12 | ```objc 13 | NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:@"Approximate Distance: 120m away"]; 14 | NSRange selectedRange = NSMakeRange(22, 4); // 4 characters, starting at index 22 15 | 16 | [string beginEditing]; 17 | 18 | [string addAttribute:NSFontAttributeName 19 | value:[NSFont fontWithName:@"Helvetica-Bold" size:12.0] 20 | range:selectedRange]; 21 | 22 | [string endEditing]; 23 | ``` 24 | 25 | -------------------------------------------------------------------------------- /content/applicationwillenterforeground-vs-applicationdidbecomeactive-applicationwillre.md: -------------------------------------------------------------------------------- 1 | # application几种状态 2 | [applicationWillEnterForeground vs. applicationDidBecomeActive, applicationWillResignActive vs. applicationDidEnterBackground](https://stackoverflow.com/questions/3712979/applicationwillenterforeground-vs-applicationdidbecomeactive-applicationwillre) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | **applicationWillEnterForeground:** 会被调用当app被重新启动 (不管是通过springboard, app切换或者URL),在APP被放入后台后,这个方法只会被执行一次,但是 **applicationDidBecomeActive:** APP启动后可能被执行很多次. 这就让 **applicationWillEnterForeground:** 成为理想的配置,针对某些重新启动后只会发生一次的事件. 11 | 12 | **applicationWillEnterForeground::** 13 | 14 | - APP被重新启动(不管是通过springboard, app切换或者URL) 15 | - 在 **applicationDidBecomeActive:**之前 16 | 17 | **applicationDidBecomeActive:** 18 | 19 | - app第一次启动并且在 `application:didFinishLaunchingWithOptions:`之后 20 | - 在 **applicationWillEnterForeground:** 如果没有 URL 需要去处理. 21 | - 在 `application:handleOpenURL:` 被调用之后. 22 | - 在 **applicationWillResignActive:** 之后:如果用户忽略电话或者短信. 23 | 24 | **applicationWillResignActive: is called:** 25 | 26 | - 当有打断比如电话进来. 27 | - 如果用户接电话会调用 **applicationDidEnterBackground:** 会被调用. 28 | - 如果用户忽略这个电话 **applicationDidBecomeActive:** 会被调用. 29 | - 当按了 home按键或者用户切换apps. 30 | - 文档说,你应该 31 | - 暂停在执行的任务 32 | - timers取消 33 | - 暂停游戏 34 | - 减小 OpenGL frame rates 35 | 36 | **applicationDidEnterBackground: is called:** 37 | 38 | - 在 **applicationWillResignActive:**之后 39 | - 文档说你应该 40 | - 释放共享资源 41 | - 保存用户数据 42 | - 取消timers 43 | - 保存app状态以便于你重建如果app被终止的话. 44 | - 不更新UI 45 | - 你有 5s的时间来处理事件直到方法返回 46 | - 如果你没有返回-app在5s内被终止 47 | - 你可以申请更多的时间通过调用 `beginBackgroundTaskWithExpirationHandler:` 48 | 49 | ![img](/images/13.png) -------------------------------------------------------------------------------- /content/best-way-to-remove-from-nsmutablearray-while-iterating.md: -------------------------------------------------------------------------------- 1 | # NSMutableArray遍历移除的最好方式? 2 | [Best way to remove from NSMutableArray while iterating?](https://stackoverflow.com/questions/111866/best-way-to-remove-from-nsmutablearray-while-iterating) 3 | 4 | [NSEnumerator](https://developer.apple.com/documentation/foundation/nsenumerator) 5 | 6 | > You send [`nextObject()`](https://developer.apple.com/documentation/foundation/nsenumerator/1409616-nextobject) repeatedly to a newly created `NSEnumerator` object to have it return the next object in the original collection. When the collection is exhausted, `nil` is returned. You cannot “reset” an enumerator after it has exhausted its collection. To enumerate a collection again, you need a new enumerator. 7 | 8 | 快速遍历的原理是根据enumerator对象内部的计数器,调用nextObject方法来实现返回下一个数组元素的,直到元素全部返回就会返回nil,于是整个enumerator对象就遍历完了;同时也提醒,以这种原理来遍历enumerator对象的话,无论对这个对象做什么操作,对象的计数器都不会被重置! 9 | 10 | 可能是我们在快速遍历的时候,移除掉一个元素,但是计数器依旧是原来的,那么在遍历到最后会继续调用nextObject方法,而此时实际上已经全部遍历完了,但是系统并不知道,还在遍历,也就是越界;当发现没有元素时,就crash了 11 | 12 | > In Objective-C, it is not safe to modify a mutable collection while enumerating through it. Some enumerators may currently allow enumeration of a collection that is modified, but this behavior is not guaranteed to be supported in the future. 13 | 14 | 遍历的时候不能对数组元素做删除操作 15 | 16 | ___ 17 | 18 | 19 | 20 | > 1 21 | 22 | 为了清晰,我一般是是先初始化一个数组用来收集要删除的项目,然后再从原来的数组里删除它: 23 | 24 | ```objc 25 | NSMutableArray *discardedItems = [NSMutableArray array]; 26 | SomeObjectClass *item; 27 | 28 | for (item in originalArrayOfItems) { 29 | if ([item shouldBeDiscarded]) 30 | [discardedItems addObject:item]; 31 | } 32 | 33 | [originalArrayOfItems removeObjectsInArray:discardedItems]; 34 | ``` 35 | 36 | > 2 37 | 38 | 其他的答案会有低效问题当一个大的数组要遍历。因为方法 `removeObject:` 和 `removeObjectsInArray:` 要做一个线性搜索, 这是一个浪费因为其实你已经知道对象在哪里了.同样,任何调用 `removeObjectAtIndex:` 在短时内要copy从索引到最后的值。 39 | 40 | 更高效的方式应该是这样: 41 | 42 | ```Objc 43 | NSMutableArray *array = ... 44 | NSMutableArray *itemsToKeep = [NSMutableArray arrayWithCapacity:[array count]]; 45 | for (id object in array) { 46 | if (! shouldRemove(object)) { 47 | [itemsToKeep addObject:object]; 48 | } 49 | } 50 | [array setArray:itemsToKeep]; 51 | ``` 52 | 53 | -------------------------------------------------------------------------------- /content/best-way-to-sort-an-nsarray-of-nsdictionary-objects.md: -------------------------------------------------------------------------------- 1 | # 字典数组的排序? 2 | [Best way to sort an NSArray of NSDictionary objects?](https://stackoverflow.com/questions/2393386/best-way-to-sort-an-nsarray-of-nsdictionary-objects) 3 | 4 | 对一个字典数组的排序 5 | 6 | ___ 7 | 8 | 9 | 10 | > 1 11 | 12 | 使用NSSortDescriptor 13 | 14 | ``` 15 | NSSortDescriptor * descriptor = [[NSSortDescriptor alloc] initWithKey:@"interest" ascending:YES]; 16 | stories = [stories sortedArrayUsingDescriptors:@[descriptor]]; 17 | ``` 18 | 19 | interest是字典里的key,stories是则是数组 20 | 21 | -------------------------------------------------------------------------------- /content/can-i-embed-a-custom-font-in-an-iphone-application.md: -------------------------------------------------------------------------------- 1 | # APP里如何使用自定义字体? 2 | [Can I embed a custom font in an iPhone application?](https://stackoverflow.com/questions/360751/can-i-embed-a-custom-font-in-an-iphone-application) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | iOS3.2之后就已经支持自定义字体,这是官方文档 11 | 12 | **Custom Font Support** 13 | Applications that want to use custom fonts can now include those fonts in their application bundle and register those fonts with the system by including the UIAppFonts key in their Info.plist file. The value of this key is an array of strings identifying the font files in the application’s bundle. When the system sees the key, it loads the specified fonts and makes them available to the application. 14 | 15 | 一旦字体在 `Info.plist`里被设置,你就可以使用了 16 | 17 | 1. 将你的自定义字体文件作为资源文件添加进项目中 18 | 2. `Info.plist` 添加一个item,Key是 `UIAppFonts`. 19 | 3. 让这个item是一个Array类型 20 | 4. 将你的字体名字(包含后缀名),填入到Array里面 21 | 5. 在代码里可以这样调用你的自定义字体 `[UIFont fontWithName:@"CustomFontName" size:12]` 22 | 23 | -------------------------------------------------------------------------------- /content/can-you-animate-a-height-change-on-a-uitableviewcell-when-selected.md: -------------------------------------------------------------------------------- 1 | # 选中UITableViewCell时动画更改高度 2 | [Can you animate a height change on a UITableViewCell when selected?](https://stackoverflow.com/questions/460014/can-you-animate-a-height-change-on-a-uitableviewcell-when-selected) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 我找到了一个简单的方法来解决这个问题 11 | 12 | 将cell的高度存在 `tableView: heightForRowAtIndexPath:`, 当你想要动画地更改高度,简单地调用这个方法: 13 | 14 | ```objc 15 | [tableView beginUpdates]; 16 | [tableView endUpdates]; 17 | ``` 18 | 19 | 你会发现你不需要reload,但是 `UITableView` 知道去重画cells, 就能动画地更改cell高度 20 | 21 | ```objc 22 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 23 | // Deselect cell 24 | [tableView deselectRowAtIndexPath:indexPath animated:TRUE]; 25 | 26 | // Toggle 'selected' state 27 | BOOL isSelected = ![self cellIsSelected:indexPath]; 28 | 29 | // Store cell 'selected' state keyed on indexPath 30 | NSNumber *selectedIndex = [NSNumber numberWithBool:isSelected]; 31 | [selectedIndexes setObject:selectedIndex forKey:indexPath]; 32 | 33 | // This is where magic happens... 34 | [demoTableView beginUpdates]; 35 | [demoTableView endUpdates]; 36 | } 37 | ``` 38 | 39 | -------------------------------------------------------------------------------- /content/cancelling-queued-performselectorafterdelay-calls.md: -------------------------------------------------------------------------------- 1 | # 取消performSelector:afterDelay 2 | [cancelling queued performSelector:afterDelay calls](https://stackoverflow.com/questions/1806445/cancelling-queued-performselectorafterdelay-calls) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | ``` 11 | [NSObject cancelPreviousPerformRequestsWithTarget:] 12 | ``` 13 | 14 | 或者 15 | 16 | ``` 17 | [NSObject cancelPreviousPerformRequestsWithTarget:selector:object:] 18 | ``` 19 | 20 | `target` 是之前调用 `performSelector:afterDelay:` 的对象. 21 | 22 | 例如: 23 | 24 | ```objc 25 | // schedule the selector 26 | [self performSelector:@selector(mySel:) withObject:nil afterDelay:5.0]; 27 | // cancel the above call (and any others on self) 28 | [NSObject cancelPreviousPerformRequestsWithTarget:self]; 29 | ``` 30 | 31 | -------------------------------------------------------------------------------- /content/catch-exception.md: -------------------------------------------------------------------------------- 1 | # 捕获异常 2 | ___ 3 | 4 | 5 | 6 | > 1 7 | 8 | 实现一个异常捕获 9 | 10 | ``` 11 | NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler); 12 | ``` 13 | 14 | ```objc 15 | void UncaughtExceptionHandler(NSException *exception) { 16 | NSArray *arr = [exception callStackSymbols]; 17 | NSString *reason = [exception reason]; 18 | NSString *name = [exception name]; 19 | NSLog(@"异常:%@\n%@\n%@",arr, reason, name); 20 | } 21 | ``` 22 | 23 | -------------------------------------------------------------------------------- /content/check-if-ios-app-is-in-background.md: -------------------------------------------------------------------------------- 1 | # 检测iOS APP是否在后台 2 | [Check if iOS app is in background](https://stackoverflow.com/questions/5835806/check-if-ios-app-is-in-background) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | App delegate会回调来显示状态改变,你可以利用这个来进行跟踪 11 | 12 | 同样,UIApplication的属性[applicationState](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/#//apple_ref/occ/instp/UIApplication/applicationState) 也可以知道状态。 13 | 14 | ```objc 15 | [[UIApplication sharedApplication] applicationState] 16 | ``` 17 | 18 | ```objc 19 | typedef NS_ENUM(NSInteger, UIApplicationState) { 20 | UIApplicationStateActive, 21 | UIApplicationStateInactive, 22 | UIApplicationStateBackground 23 | } NS_ENUM_AVAILABLE_IOS(4_0); 24 | ``` 25 | 26 | -------------------------------------------------------------------------------- /content/checking-a-null-value-in-objective-c-that-has-been-returned-from-a-json-string.md: -------------------------------------------------------------------------------- 1 | # JSON字符串里的null处理 2 | [Checking a null value in Objective-C that has been returned from a JSON string](https://stackoverflow.com/questions/4839355/checking-a-null-value-in-objective-c-that-has-been-returned-from-a-json-string) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | Json字符串里的null,如果放到字典里,会被解析成`[NSNull null]`,如果打印的话,log会是,所以可以这样进行辨别 11 | 12 | ``` 13 | if (tel == (id)[NSNull null]) { 14 | // tel is null 15 | } 16 | 或者 17 | if ([tel isKindOfClass:[NSNull class]]) 18 | ``` 19 | 20 | 究其原因,是因为在Objective-c里,不能有nil,空元素一律用[NSNull null]来表示 -------------------------------------------------------------------------------- /content/class-vs-import.md: -------------------------------------------------------------------------------- 1 | # @class vs. #import? 2 | [@class vs. #import](https://stackoverflow.com/questions/322597/class-vs-import) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 如果你`@class MyCoolClass`,编译器会这样 11 | 12 | ``` 13 | MyCoolClass *myObject; 14 | ``` 15 | 16 | 编译器除了需要`MyCoolClass` 是一个可用的类,不需要关心其他的,它应该保留一个空间来存放一个指针来指向。这样,在头文件里,`@class`可以节省90%的时间。 17 | 18 | 然而,如果你需要创建或者接近myobject的成员,你需要让编译器知道这些方法是什么,这种情况下,你需要`#import "MyCoolClass.h"`, 用来告诉编译器附加信息而不只是说‘这是一个类’ -------------------------------------------------------------------------------- /content/constants-in-objective-c.md: -------------------------------------------------------------------------------- 1 | # 如何声明一个全局常量? 2 | [Constants in Objective-C](https://stackoverflow.com/questions/538996/constants-in-objective-c) 3 | 4 | 问题:如何声明一个全局的常量字符串 5 | 6 | ___ 7 | 8 | 9 | 10 | > 1 11 | 12 | 你可以在.h文件里这样 13 | 14 | ``` 15 | // Constants.h 16 | FOUNDATION_EXPORT NSString *const MyFirstConstant; 17 | FOUNDATION_EXPORT NSString *const MySecondConstant; 18 | //etc. 19 | ``` 20 | 21 | 如果不是C/C++混编,你可以用 `extern` 替换 `FOUNDATION_EXPORT` 。需要将.h文件导入到需要使用这个常量的文件中 22 | 23 | 在.m文件里则这样声明: 24 | 25 | ``` 26 | // Constants.m 27 | NSString *const MyFirstConstant = @"FirstConstant"; 28 | NSString *const MySecondConstant = @"SecondConstant"; 29 | ``` 30 | 31 | 这种声明比`#define`有一个优势在于(`stringInstance == MyFirstConstant`) 来指针比较而不是 (`[stringInstance isEqualToString:MyFirstConstant]`)进行字符串比较,前者效率更高且易读。 -------------------------------------------------------------------------------- /content/creating-a-blurring-overlay-view.md: -------------------------------------------------------------------------------- 1 | # 创建一个带模糊效果的View 2 | [Creating a blurring overlay view](https://stackoverflow.com/questions/17041669/creating-a-blurring-overlay-view) 3 | 4 | 如何达到以下效果? 5 | 6 | ![img](/images/06.jpg) 7 | 8 | ___ 9 | 10 | 11 | 12 | > 1 13 | 14 | 你可以用 `UIVisualEffectView` 来达到这个效果. 这是个原生API可以达到很好的效果和省电,也容易声明: 15 | 16 | **Swift:** 17 | 18 | ```swift 19 | //only apply the blur if the user hasn't disabled transparency effects 20 | if !UIAccessibilityIsReduceTransparencyEnabled() { 21 | view.backgroundColor = .clear 22 | 23 | let blurEffect = UIBlurEffect(style: .dark) 24 | let blurEffectView = UIVisualEffectView(effect: blurEffect) 25 | //always fill the view 26 | blurEffectView.frame = self.view.bounds 27 | blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight] 28 | 29 | view.addSubview(blurEffectView) //if you have more UIViews, use an insertSubview API to place it where needed 30 | } else { 31 | view.backgroundColor = .black 32 | } 33 | ``` 34 | 35 | **Objective-C:** 36 | 37 | ```objc 38 | //only apply the blur if the user hasn't disabled transparency effects 39 | if (!UIAccessibilityIsReduceTransparencyEnabled()) { 40 | self.view.backgroundColor = [UIColor clearColor]; 41 | 42 | UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; 43 | UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect]; 44 | //always fill the view 45 | blurEffectView.frame = self.view.bounds; 46 | blurEffectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 47 | 48 | [self.view addSubview:blurEffectView]; //if you have more UIViews, use an insertSubview API to place it where needed 49 | } else { 50 | self.view.backgroundColor = [UIColor blackColor]; 51 | } 52 | ``` 53 | 54 | 另外,如果你是要presenting这个Viewcontroller来模糊遮挡底下的内容,你需要设置 modal presentation style 成 Over Current Context,并且背景颜色也要设置为空白来保证底下的内容依旧可见。 -------------------------------------------------------------------------------- /content/deep-copying-an-nsarray.md: -------------------------------------------------------------------------------- 1 | # NSArray的深拷贝 2 | [Deep copying an NSArray](https://stackoverflow.com/questions/647260/deep-copying-an-nsarray) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | #### 默认的copy会对NSArray进行浅拷贝 11 | 12 | 因为调用 `copy` 其实就是调用 `copyWithZone:NULL` 进行拷贝默认的空间. `copy` 不会进行深拷贝.不可变对象只会给一个浅拷贝 13 | 14 | - [immutableObject copy] // 浅复制 15 | - [immutableObject mutableCopy] //单层深复制 //NSArray层级的深复制 16 | - [mutableObject copy] //单层深复制 17 | - [mutableObject mutableCopy] //单层深复制 18 | 19 | #### initWithArray:CopyItems: 单层深拷贝 20 | 21 | ``` 22 | NSArray *deepCopyArray = [[NSArray alloc] initWithArray:someArray copyItems:YES]; 23 | ``` 24 | 25 | #### `NSCoding`进行真正的深拷贝 26 | 27 | ``` 28 | NSArray *trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:oldArray]]; 29 | ``` 30 | 31 | 这种拷贝可以对数组里面的元素也进行深拷贝。 32 | 33 | 参考苹果官方文档[集合类拷贝](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Collections/Articles/Copying.html#//apple_ref/doc/uid/TP40010162-SW1) -------------------------------------------------------------------------------- /content/detect-if-the-device-is-iphone-x.md: -------------------------------------------------------------------------------- 1 | # 判断设备型号iphone X 2 | [Detect if the device is iPhone X](https://stackoverflow.com/questions/46192280/detect-if-the-device-is-iphone-x) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 可以根据设备屏幕的大小来判断设备型号 11 | 12 | ![img](/images/09.png) 13 | 14 | **swift 3 and above** 15 | 16 | ```swift 17 | if UIDevice().userInterfaceIdiom == .phone { 18 | switch UIScreen.main.nativeBounds.height { 19 | case 1136: 20 | print("iPhone 5 or 5S or 5C") 21 | case 1334: 22 | print("iPhone 6/6S/7/8") 23 | case 2208: 24 | print("iPhone 6+/6S+/7+/8+") 25 | case 2436: 26 | print("iPhone X") 27 | default: 28 | print("unknown") 29 | } 30 | } 31 | ``` 32 | 33 | **objective C** 34 | 35 | ```objc 36 | if([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPhone) { 37 | 38 | switch ((int)[[UIScreen mainScreen] nativeBounds].size.height) { 39 | 40 | case 1136: 41 | printf("iPhone 5 or 5S or 5C"); 42 | break; 43 | case 1334: 44 | printf("iPhone 6/6S/7/8"); 45 | break; 46 | case 2208: 47 | printf("iPhone 6+/6S+/7+/8+"); 48 | break; 49 | case 2436: 50 | printf("iPhone X"); 51 | break; 52 | default: 53 | printf("unknown"); 54 | } 55 | } 56 | ``` -------------------------------------------------------------------------------- /content/detecting-taps-on-attributed-text-in-a-uitextview-in-ios.md: -------------------------------------------------------------------------------- 1 | # 检测UITextView上的点击了字符串 2 | [Detecting taps on attributed text in a UITextView in iOS](https://stackoverflow.com/questions/19332283/detecting-taps-on-attributed-text-in-a-uitextview-in-ios) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 1、自定义一个attributed string 11 | 12 | ```Objc 13 | NSAttributedString* attributedString = [[NSAttributedString alloc] initWithString:@"a clickable word" attributes:@{ @"myCustomTag" : @(YES) }]; 14 | [paragraph appendAttributedString:attributedString]; 15 | ``` 16 | 17 | 2、创建一个UITextView来显示字符串,并且在上面加上手势 18 | 19 | ```objc 20 | - (void)textTapped:(UITapGestureRecognizer *)recognizer 21 | { 22 | UITextView *textView = (UITextView *)recognizer.view; 23 | 24 | // 定位点击的坐标位置 25 | NSLayoutManager *layoutManager = textView.layoutManager; 26 | CGPoint location = [recognizer locationInView:textView]; 27 | location.x -= textView.textContainerInset.left; 28 | location.y -= textView.textContainerInset.top; 29 | 30 | // 找到哪些字符串被点击了 31 | NSUInteger characterIndex; 32 | characterIndex = [layoutManager characterIndexForPoint:location 33 | inTextContainer:textView.textContainer 34 | fractionOfDistanceBetweenInsertionPoints:NULL]; 35 | 36 | if (characterIndex < textView.textStorage.length) { 37 | 38 | NSRange range; 39 | id value = [textView.attributedText attribute:@"myCustomTag" atIndex:characterIndex effectiveRange:&range]; 40 | 41 | // 要做的操作 42 | 43 | NSLog(@"%@, %d, %d", value, range.location, range.length); 44 | } 45 | } 46 | ``` 47 | 48 | -------------------------------------------------------------------------------- /content/detecting-when-the-back-button-is-pressed-on-a-navbar.md: -------------------------------------------------------------------------------- 1 | # 监测NavBar的返回按钮被点击 2 | [Detecting when the 'back' button is pressed on a navbar](https://stackoverflow.com/questions/8228411/detecting-when-the-back-button-is-pressed-on-a-navbar) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | iOS 5之后用这个方法很方便 11 | 12 | `- (BOOL)isMovingFromParentViewController`: 13 | 14 | ``` 15 | - (void)viewWillDisappear:(BOOL)animated { 16 | [super viewWillDisappear:animated]; 17 | 18 | if (self.isMovingFromParentViewController) { 19 | // Do your stuff here 20 | } 21 | } 22 | ``` 23 | 24 | `- (BOOL)isMovingFromParentViewController` 返回YES就是在pop出去 25 | 26 | 如果是 presenting modal view controllers 应该用 `- (BOOL)isBeingDismissed` : 27 | 28 | ``` 29 | - (void)viewWillDisappear:(BOOL)animated { 30 | [super viewWillDisappear:animated]; 31 | 32 | if (self.isBeingDismissed) { 33 | // Do your stuff here 34 | } 35 | } 36 | ``` 37 | 38 | 综上可以,这样判断 39 | 40 | ``` 41 | - (void)viewWillDisappear:(BOOL)animated { 42 | [super viewWillDisappear:animated]; 43 | 44 | if (self.isMovingFromParentViewController || self.isBeingDismissed) { 45 | // 这里是返回上一个界面 46 | } 47 | } 48 | ``` -------------------------------------------------------------------------------- /content/difference-between-nil-nil-and-null-in-objective-c.md: -------------------------------------------------------------------------------- 1 | # nil, NIL, NULL, NSNull的区别? 2 | [Difference between nil, NIL and, null in Objective-C](https://stackoverflow.com/questions/5908936/difference-between-nil-nil-and-null-in-objective-c) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | #### nil 11 | 12 | `nil` 是 Objective-C 对象空值的意思, 对应于未知类型 `id` 或者其他 Objective-C类型的对象 。 13 | 14 | ```objc 15 | NSString *someString = nil; 16 | NSURL *someURL = nil; 17 | id someObject = nil; 18 | 19 | if (anotherObject == nil) // do something 20 | ``` 21 | 22 | #### Nil 23 | 24 | `Nil` 是 Objective-C 类为空, 对应于 `Class`. 因为大部分代码不需要引用class变量,所以这个并不常用。 25 | 26 | ```objc 27 | Class someClass = Nil; 28 | Class anotherClass = [NSString class]; 29 | ``` 30 | 31 | #### NULL 32 | 33 | `NULL` C指针为空值。 34 | 35 | ```objc 36 | int *pointerToInt = NULL; 37 | char *pointerToChar = NULL; 38 | struct TreeNode *rootNode = NULL; 39 | ``` 40 | 41 | #### NSNull 42 | 43 | `NSNull` 是一个类用来代表空对象,实际上就是 `+[NSNull null]`. 与 `nil` 不一样因为空 `nil` 就是字面上的孔不是一个对象. `NSNull`的实例对象,是一个对象。 44 | 45 | `NSNull` 经常用在 Foundation collections 因为它们不能存储 `nil` 值. 比如在dictionaries, `-objectForKey:` 返回一个 `nil` 对应的key没有存储对象在里面,这个key没有添加进字典里. 如果你想用来表明,这个kety清楚地被添加进了,只不过没有值,你应该用 `[NSNull null]`. 46 | 47 | ```objc 48 | NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 49 | [dict setObject:[NSNull null] forKey:@"someKey"]; 50 | 51 | // 下面这种赋值时错误的,因为不能设nil 52 | NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 53 | [dict setObject:nil forKey:@"someKey"]; 54 | ``` 55 | 56 | 对于nil,只有在NSArray初始化时在作为结束的一个标志。这种情况也不是作为元素存储。 57 | 58 | ``` 59 | NSArray *array = [NSArray arrayWithObjects:@"one", @"two", nil]; 60 | ``` -------------------------------------------------------------------------------- /content/difference-between-objectforkey-and-valueforkey.md: -------------------------------------------------------------------------------- 1 | # objectForKey和valueForKey有什么区别? 2 | [Difference between objectForKey and valueForKey?](https://stackoverflow.com/questions/1062183/difference-between-objectforkey-and-valueforkey) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | `objectForKey:` 是一个 `NSDictionary` 方法. 一个 `NSDictionary` 是一个集合类如同 `NSArray`, 除了不能用index来取值, 用key来区分不同的item.key就是你提供的字符串. 没有两个对象有相同的key的可能 (就如同 `NSArray`里的对象不会有相同的序号 ). 11 | 12 | `valueForKey:` 是一个KVC方法. 任何class都适用这个方法. `valueForKey:` 可以让你通过它的key来获取这个对象. 13 | 14 | 例如, 对于实例对象,我有一个 `Account` 类有个属性 `accountNumber`, 我可以这样: 15 | 16 | ```objc 17 | NSNumber *anAccountNumber = [NSNumber numberWithInt:12345]; 18 | Account *newAccount = [[Account alloc] init]; 19 | 20 | [newAccount setAccountNumber:anAccountNUmber]; 21 | 22 | NSNumber *anotherAccountNumber = [newAccount accountNumber]; 23 | ``` 24 | 25 | 通过KVC,我可以动态的获取这个对象 26 | 27 | ```objc 28 | NSNumber *anAccountNumber = [NSNumber numberWithInt:12345]; 29 | Account *newAccount = [[Account alloc] init]; 30 | [newAccount setValue:anAccountNumber forKey:@"accountNumber"]; 31 | NSNumber *anotherAccountNumber = [newAccount valueForKey:@"accountNumber"]; 32 | ``` 33 | 34 | -------------------------------------------------------------------------------- /content/dispatch-sync-always-scheduling-a-block-on-main-thread.md: -------------------------------------------------------------------------------- 1 | # Dispatch_sync 2 | [dispatch_sync always scheduling a block on Main Thread](https://stackoverflow.com/questions/13972048/dispatch-sync-always-scheduling-a-block-on-main-thread) 3 | 4 | ``` 5 | dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 6 | 7 | if ([NSThread isMainThread]) { 8 | NSLog(@"Main Thread"); 9 | } 10 | else 11 | NSLog(@"Not on Main Thread"); 12 | 13 | //Some Process 14 | }); 15 | ``` 16 | 17 | 打印结果是Main Thread 18 | 19 | ___ 20 | 21 | 22 | 23 | > 1 24 | 25 | 苹果官方文档[dispatch_sync](https://developer.apple.com/documentation/dispatch/1452870-dispatch_sync?language=objc) 26 | 27 | > Submits a block to a dispatch queue for synchronous execution. Unlike [`dispatch_async`](https://developer.apple.com/documentation/dispatch/1453057-dispatch_async?language=objc), this function does not return until the block has finished. Calling this function and targeting the current queue results in deadlock. 28 | > 29 | > Unlike with `dispatch_async`, no retain is performed on the target queue. Because calls to this function are synchronous, it "borrows" the reference of the caller. Moreover, no `Block_copy` is performed on the block. 30 | > 31 | > As an optimization, this function invokes the block on the current thread when possible. 32 | 33 | 调用dispatch_sync在当前队列会导致死锁。另外,最优化处理,dispatch_sync在在当前线程上执行block 34 | 35 | -------------------------------------------------------------------------------- /content/does-the-apns-device-token-ever-change-once-created.md: -------------------------------------------------------------------------------- 1 | # APNs的Token创建后会更新吗? 2 | [Does the APNS device token ever change, once created?](https://stackoverflow.com/questions/6652242/does-the-apns-device-token-ever-change-once-created) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | [APNS](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/HandlingRemoteNotifications.html#//apple_ref/doc/uid/TP40008194-CH6-SW1) 11 | 12 | > Never cache device tokens in your app; instead, get them from the system when you need them. APNs issues a new device token to your app when certain events happen. The device token is guaranteed to be different, for example, when a user restores a device from a backup, when the user installs your app on a new device, and when the user reinstalls the operating system. Fetching the token, rather than relying on a cache, ensures that you have the current device token needed for your provider to communicate with APNs. When you attempt to fetch a device token but it has not changed, the fetch method returns quickly. 13 | 14 | 不要缓存device tokens,相反,你应该在需要的时候去获取它, APNs 会在一些特定情况下更新token,比如,当用户从备份里恢复一个设备,用户安装APP到一个新设备,用户重新安装系统。所以不要去依赖缓存token,而应当在需要的时候去获取。 -------------------------------------------------------------------------------- /content/draw-color-export-image.md: -------------------------------------------------------------------------------- 1 | # 画图并导出沙盒 2 | ___ 3 | 4 | 5 | 6 | > 1 7 | 8 | ```objc 9 | UIImage * image = [UIImage imageNamed:@"01.png"]; 10 | CGSize size = CGSizeMake(1024, 1024); 11 | UIGraphicsBeginImageContext(size); 12 | CGContextRef context = UIGraphicsGetCurrentContext(); 13 | CGContextSetFillColorWithColor(context, [RGBFromHex(0x0FBEEC) CGColor]); 14 | CGContextFillRect(context, CGRectMake(0, 0, 1024, 1024)); 15 | 16 | [image drawInRect:CGRectMake(0, 0, size.width, size.height)]; 17 | UIImage *resultingImage =UIGraphicsGetImageFromCurrentImageContext(); 18 | UIGraphicsEndImageContext(); 19 | 20 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES); 21 | NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"new.png"]; // 保存文件的名称 22 | BOOL result = [UIImagePNGRepresentation(resultingImage) writeToFile: filePath atomically:YES]; 23 | ``` -------------------------------------------------------------------------------- /content/duplicate-simulators.md: -------------------------------------------------------------------------------- 1 | # Xcode重复出现多个模拟器的处理方法? 2 | ___ 3 | 4 | 5 | 6 | > 1 7 | 8 | 首先完全退出Xcode和模拟器 9 | 10 | 然后在终端输入: 11 | 12 | ```shell 13 | sudo killall -9 com.apple.CoreSimulator.CoreSimulatorService 14 | 15 | rm -rf ~/Library/Developer/CoreSimulator/Devices 16 | ``` -------------------------------------------------------------------------------- /content/easy-way-to-see-saved-nsuserdefaults.md: -------------------------------------------------------------------------------- 1 | # 查看存储在NSUserDefaults的值 2 | [Easy way to see saved NSUserDefaults?](https://stackoverflow.com/questions/1676938/easy-way-to-see-saved-nsuserdefaults) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 在模拟器中的APP,你可以去这个路径查看 11 | 12 | ``` 13 | /users/your user name/Library/Application Support/iPhone Simulator//Applications 14 | ``` 15 | 16 | 这个目录有一个GUID文件夹,如果你有好几个APP在里面,会有几个文件夹,所以你应该找到你的app binary: 17 | 18 | ``` 19 | find . -name foo.app 20 | ./1BAB4C83-8E7E-4671-AC36-6043F8A9BFA7/foo.app 21 | ``` 22 | 23 | 然后去对应的文件夹: 24 | 25 | ``` 26 | cd 1BAB4C83-8E7E-4671-AC35-6043F8A9BFA7/Library/Preferences 27 | ``` 28 | 29 | 你应该可以看到一个文件: 30 | 31 | ``` 32 | .foo.pList 33 | ``` 34 | 35 | 打开这个文件夹就能找到你要的值了 36 | 37 | > 2 38 | 39 | 可以再log里打印出来: 40 | 41 | Keys: 42 | 43 | ``` 44 | NSLog(@"%@", [[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys]); 45 | ``` 46 | 47 | Keys and values: 48 | 49 | ``` 50 | NSLog(@"%@", [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]); 51 | ``` 52 | 53 | -------------------------------------------------------------------------------- /content/filtering-nsarray-into-a-new-nsarray-in-objective-c.md: -------------------------------------------------------------------------------- 1 | # 数组过滤 2 | [filtering NSArray into a new NSArray in objective-c](https://stackoverflow.com/questions/110332/filtering-nsarray-into-a-new-nsarray-in-objective-c) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | `NSArray` 提供了 **filteredArrayUsingPredicate:** 方法来进行过滤 11 | 12 | ```objc 13 | NSMutableArray *array = [NSMutableArray arrayWithObjects:@"Bill", @"Ben", @"Chris", @"Melissa", nil]; 14 | 15 | NSPredicate *bPredicate = [NSPredicate predicateWithFormat:@"SELF beginswith[c] 'b'"]; 16 | NSArray *beginWithB = [array filteredArrayUsingPredicate:bPredicate]; 17 | // beginWithB contains { @"Bill", @"Ben" }. 18 | ``` 19 | 20 | 或者用Block: 21 | 22 | ```objc 23 | NSArray *filteredArray = [array filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id object, NSDictionary *bindings) { 24 | return [object shouldIKeepYou]; // Return YES for each object you want in filteredArray. 25 | }]]; 26 | ``` 27 | 28 | #### Swift: 29 | 30 | ```swift 31 | nsArray = nsArray.filter { $0.shouldIKeepYou() } 32 | ``` -------------------------------------------------------------------------------- /content/get-parts-of-a-nsurl-in-objective-c.md: -------------------------------------------------------------------------------- 1 | # NSURL里的部分信息 2 | [Get parts of a NSURL in objective-c](https://stackoverflow.com/questions/3692947/get-parts-of-a-nsurl-in-objective-c) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | ``` 11 | http://foobar:nicate@example.com:8080/some/path/file.html;params-here?foo=bar#baz 12 | ``` 13 | 14 | 对于上面这样的一个URL,通过实例方法可以获取部分信息 15 | 16 | - `-[NSURL scheme]` = http 17 | - `-[NSURL resourceSpecifier]` = (从 // 到 URL的结尾) 18 | - `-[NSURL user]` = foobar 19 | - `-[NSURL password]` = nicate 20 | - `-[NSURL host]` = example.com 21 | - `-[NSURL port]` = 8080 22 | - `-[NSURL path]` = /some/path/file.html 23 | - `-[NSURL pathComponents]` = @["/", "some", "path", "file.html"] (note that the initial / is part of it) 24 | - `-[NSURL lastPathComponent]` = file.html 25 | - `-[NSURL pathExtension]` = html 26 | - `-[NSURL parameterString]` = params-here 27 | - `-[NSURL query]` = foo=bar 28 | - `-[NSURL fragment]` = baz -------------------------------------------------------------------------------- /content/how-can-i-create-a-uicolor-from-a-hex-string.md: -------------------------------------------------------------------------------- 1 | # 16进制的UIColor 2 | [How can I create a UIColor from a hex string?](https://stackoverflow.com/questions/1560081/how-can-i-create-a-uicolor-from-a-hex-string) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 可以通过这种方式 11 | 12 | ```objc 13 | #define UIColorFromRGB(rgbValue) \ 14 | [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \ 15 | green:((float)((rgbValue & 0x00FF00) >> 8))/255.0 \ 16 | blue:((float)((rgbValue & 0x0000FF) >> 0))/255.0 \ 17 | alpha:1.0] 18 | ``` 19 | 20 | ```objc 21 | label.textColor = UIColorFromRGB(0xBC1128); 22 | ``` 23 | 24 | -------------------------------------------------------------------------------- /content/how-can-i-programmatically-get-the-mac-address-of-an-iphone.md: -------------------------------------------------------------------------------- 1 | # 设备唯一标识 2 | [How can I programmatically get the MAC address of an iphone](https://stackoverflow.com/questions/677530/how-can-i-programmatically-get-the-mac-address-of-an-iphone) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 在iOS7之后,不能获取设备的Mac地址,会返回02:00:00:00:00:00 11 | 12 | 设备的唯一标识 13 | 14 | import "UIDevice+Identifier.h" 15 | 16 | ```objc 17 | - (NSString *) identifierForVendor1 18 | { 19 | if ([[UIDevice currentDevice] respondsToSelector:@selector(identifierForVendor)]) { 20 | return [[[UIDevice currentDevice] identifierForVendor] UUIDString]; 21 | } 22 | return @""; 23 | } 24 | ``` 25 | 26 | -------------------------------------------------------------------------------- /content/how-disable-copy-cut-select-select-all-in-uitextview.md: -------------------------------------------------------------------------------- 1 | # 禁用UITextView的粘贴板功能 2 | [How disable Copy, Cut, Select, Select All in UITextView](https://stackoverflow.com/questions/1426731/how-disable-copy-cut-select-select-all-in-uitextview) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 禁用粘贴板功能很简单,定义一个 `UITextView` 的子类重写 `canPerformAction:withSender:` 返回 `NO` : 11 | 12 | ```objc 13 | - (BOOL)canPerformAction:(SEL)action withSender:(id)sender 14 | { 15 | if (action == @selector(paste:)) 16 | return NO; 17 | return [super canPerformAction:action withSender:sender]; 18 | } 19 | ``` -------------------------------------------------------------------------------- /content/how-do-i-animate-constraint-changes.md: -------------------------------------------------------------------------------- 1 | # 更改布局时如何用动画? 2 | [How do I animate constraint changes?](https://stackoverflow.com/questions/12622424/how-do-i-animate-constraint-changes) 3 | 4 | 问题: 5 | 6 | ``` 7 | - (void)moveBannerOffScreen { 8 | [UIView animateWithDuration:5 9 | animations:^{ 10 | _addBannerDistanceFromBottomConstraint.constant = -32; 11 | }]; 12 | bannerIsVisible = FALSE; 13 | } 14 | 15 | - (void)moveBannerOnScreen { 16 | [UIView animateWithDuration:5 17 | animations:^{ 18 | _addBannerDistanceFromBottomConstraint.constant = 0; 19 | }]; 20 | bannerIsVisible = TRUE; 21 | } 22 | ``` 23 | 24 | 以上代码,可以变更布局,但是变更的时候没有动画,如何才能有动画呢? 25 | 26 | ___ 27 | 28 | 29 | 30 | > 1 31 | 32 | 两个重点 33 | 34 | 1. 在animation block之前你需要调用 `layoutIfNeeded` ,苹果建议在动画block之前调用这个方法以确保所有的布局依赖都已经建立完成 。 35 | 2. 你需要对 **parent view** (e.g. `self.view`)操作而不是子View。这样的化,就会更新所有的布局,包括其他动画变更有改变的布局。 36 | 37 | ```objc 38 | - (void)moveBannerOffScreen { 39 | [self.view layoutIfNeeded]; 40 | 41 | _addBannerDistanceFromBottomConstraint.constant = -32; 42 | [UIView animateWithDuration:5 43 | animations:^{ 44 | [self.view layoutIfNeeded]; // Called on parent view 45 | }]; 46 | bannerIsVisible = FALSE; 47 | } 48 | 49 | - (void)moveBannerOnScreen { 50 | [self.view layoutIfNeeded]; 51 | 52 | _addBannerDistanceFromBottomConstraint.constant = 0; 53 | [UIView animateWithDuration:5 54 | animations:^{ 55 | [self.view layoutIfNeeded]; // Called on parent view 56 | }]; 57 | bannerIsVisible = TRUE; 58 | } 59 | ``` 60 | 61 | -------------------------------------------------------------------------------- /content/how-do-i-check-if-a-string-contains-another-string-in-objective-c.md: -------------------------------------------------------------------------------- 1 | # 如何判断一个字符串包含另外一个字符串? 2 | https://stackoverflow.com/questions/2753956/how-do-i-check-if-a-string-contains-another-string-in-objective-c 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | ``` 11 | NSString *string = @"hello bla bla"; 12 | if ([string rangeOfString:@"bla"].location == NSNotFound) { 13 | NSLog(@"string does not contain bla"); 14 | } else { 15 | NSLog(@"string contains bla!"); 16 | } 17 | ``` 18 | 19 | 如果是iOS8以上可以用以下的方法,注意,如果是iOS7会导致崩溃 20 | 21 | ``` 22 | NSString *string = @"hello bla blah"; 23 | if ([string containsString:@"bla"]) { 24 | NSLog(@"string contains bla!"); 25 | } else { 26 | NSLog(@"string does not contain bla"); 27 | } 28 | ``` 29 | 30 | ___ 31 | 32 | > 2 33 | 34 | 手动写一个算法: 35 | 36 | 核心思想:将a中的每个字符对应的素数相乘,得到一个整数。然后,让字符串b中的每一个字符也对应相应的素数,再用b中的每个字符对应的素数除上面得到的整数。如果有余数,说明结果为false,立即退出程序;如果整个过程中没有余数,则说明b是a的子集。 37 | 38 | ``` 39 | bool StringContain(string &a, string &b) 40 | { 41 | const int p[26]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53, 42 | 59,61,67,71,73,79,83,89,97,101}; 43 | int result=1;//存放字符串a每个字符对应素数的乘积 44 | for(int i=0; i 1 9 | 10 | 主要诀窍是你得有一个View(不是UIViewController)来成为firstResponder接收摇动事件的信息: 11 | 12 | ```objc 13 | @implementation ShakingView 14 | 15 | - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event 16 | { 17 | if ( event.subtype == UIEventSubtypeMotionShake ) 18 | { 19 | // Put in code here to handle shake 20 | } 21 | 22 | if ( [super respondsToSelector:@selector(motionEnded:withEvent:)] ) 23 | [super motionEnded:motion withEvent:event]; 24 | } 25 | 26 | - (BOOL)canBecomeFirstResponder 27 | { return YES; } 28 | 29 | @end 30 | ``` 31 | 32 | 在View Controller,你需要设置这个shakeView成为firstResponder 33 | 34 | ```objc 35 | - (void) viewWillAppear:(BOOL)animated 36 | { 37 | [shakeView becomeFirstResponder]; 38 | [super viewWillAppear:animated]; 39 | } 40 | - (void) viewWillDisappear:(BOOL)animated 41 | { 42 | [shakeView resignFirstResponder]; 43 | [super viewWillDisappear:animated]; 44 | } 45 | ``` 46 | 47 | 不要忘了,如果你有其他的View有可能成为第一响应者(比如搜索框或者文字输入框),你应该重新设置shakingView成为第一响应者当其他View完成后。 -------------------------------------------------------------------------------- /content/how-do-i-sort-an-nsmutablearray-with-custom-objects-in-it.md: -------------------------------------------------------------------------------- 1 | # 如何在NSMutableArray里对自定义对象进行排序? 2 | 3 | https://stackoverflow.com/questions/805547/how-do-i-sort-an-nsmutablearray-with-custom-objects-in-it 4 | 5 | 问题: 6 | 7 | drinkDetails是一个数组,有一个Person对象,里面有个类型为NSDate的birthDate属性,想根据这个属性对Person排序 8 | 9 | ___ 10 | 11 | 12 | 13 | > 1 14 | 15 | #### Compare Method 16 | 17 | 在Person类里实现一个compare方法: 18 | 19 | ``` 20 | - (NSComparisonResult)compare:(Person *)otherObject { 21 | return [self.birthDate compare:otherObject.birthDate]; 22 | } 23 | 24 | NSArray *sortedArray = [drinkDetails sortedArrayUsingSelector:@selector(compare:)]; 25 | ``` 26 | 27 | #### NSSortDescriptor 28 | 29 | ``` 30 | NSSortDescriptor *sortDescriptor; 31 | sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthDate" 32 | ascending:YES]; 33 | NSArray *sortedArray = [drinkDetails sortedArrayUsingDescriptors:@[sortDescriptor]]; 34 | ``` 35 | 36 | #### Blocks 37 | 38 | ``` 39 | NSArray *sortedArray; 40 | sortedArray = [drinkDetails sortedArrayUsingComparator:^NSComparisonResult(id a, id b) { 41 | NSDate *first = [(Person*)a birthDate]; 42 | NSDate *second = [(Person*)b birthDate]; 43 | return [first compare:second]; 44 | }]; 45 | ``` 46 | 47 | 效率 48 | 49 | `-compare:` 和block方法会更快一些, 一般来说,使用 `NSSortDescriptor` 依赖于KVC. 优势在于提供了一种方式通过使用data来进行排序而不是代码,这样的话,使得一些排序更容易,比如,用户可以通过点击header行来对 `NSTableView` 进行排序. -------------------------------------------------------------------------------- /content/how-does-synchronized-lock-unlock-in-objective-c.md: -------------------------------------------------------------------------------- 1 | # @synchronized是如何加锁/解锁? 2 | [How does @synchronized lock/unlock in Objective-C?](https://stackoverflow.com/questions/1215330/how-does-synchronized-lock-unlock-in-objective-c) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | Objective-C语言里synchronization用的是互斥锁,就如同 `NSLock` . 虽然在有一些小的技术差异,但把它们看作在一个共同的(更原始的)实体之上实现的两个单独的接口是可以的。 11 | 12 | 特别地,如果用 `NSLock` 你有一个明确的锁,而如果用 `@synchronized` 你有一个隐含的锁与你需要同步的对象相关联. 编译可以明白,在实际操作上基本上是一样的. 13 | 14 | 你可以认为 `@synchronized` 会被编译器改写成: 15 | 16 | ```objc 17 | - (NSString *)myString { 18 | @synchronized(self) { 19 | return [[myString retain] autorelease]; 20 | } 21 | } 22 | ``` 23 | 24 | 被转换成 25 | 26 | ```objc 27 | - (NSString *)myString { 28 | NSString *retval = nil; 29 | pthread_mutex_t *self_mutex = LOOK_UP_MUTEX(self); 30 | pthread_mutex_lock(self_mutex); 31 | retval = [[myString retain] autorelease]; 32 | pthread_mutex_unlock(self_mutex); 33 | return retval; 34 | } 35 | ``` 36 | 37 | 这个并不完全准备,因为实际转换会更复杂而且用上了递归锁,但是你应该可以看到重点。 38 | 39 | > 2 40 | 41 | 在Objective-C, 一个 `@synchronized` block自动处理了加锁和解锁的操作. 运行时会自动生成一个递归锁NSRecursiveLock加在你想要同步的对象上面. 这就是为什么你没有看到你的NSLock子类的日志消息 - 你同步的对象可以是任何东西,而不仅仅是一个NSLock。 42 | 43 | 一般来说, `@synchronized (...)` 是一个很方便的结构让你的代码顺畅化. 就如果大多数简化的抽象一样,会有一些开销。但是,当你用这样的结构时,原始的性能应该不是作为最高的目标 -------------------------------------------------------------------------------- /content/how-to-add-a-border-just-on-the-top-side-of-a-uiview.md: -------------------------------------------------------------------------------- 1 | # 给UIView的一边添加border 2 | [How to add a border just on the top side of a UIView](https://stackoverflow.com/questions/17355280/how-to-add-a-border-just-on-the-top-side-of-a-uiview) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 可以把Boder作为一个CALayer添加上去: 11 | 12 | #### Objective-C: 13 | 14 | ```objc 15 | - (CALayer *)prefix_addUpperBorder:(UIRectEdge)edge color:(UIColor *)color thickness:(CGFloat)thickness 16 | { 17 | CALayer *border = [CALayer layer]; 18 | 19 | switch (edge) { 20 | case UIRectEdgeTop: 21 | border.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), thickness); 22 | break; 23 | case UIRectEdgeBottom: 24 | border.frame = CGRectMake(0, CGRectGetHeight(self.frame) - thickness, CGRectGetWidth(self.frame), thickness); 25 | break; 26 | case UIRectEdgeLeft: 27 | border.frame = CGRectMake(0, 0, thickness, CGRectGetHeight(self.frame)); 28 | break; 29 | case UIRectEdgeRight: 30 | border.frame = CGRectMake(CGRectGetWidth(self.frame) - thickness, 0, thickness, CGRectGetHeight(self.frame)); 31 | break; 32 | default: 33 | break; 34 | } 35 | 36 | border.backgroundColor = color.CGColor; 37 | 38 | [self.layer addSublayer:border]; 39 | 40 | return border; 41 | } 42 | ``` 43 | 44 | #### Swift 45 | 46 | ```objc 47 | extension CALayer { 48 | 49 | func addBorder(edge: UIRectEdge, color: UIColor, thickness: CGFloat) { 50 | 51 | let border = CALayer() 52 | 53 | switch edge { 54 | case UIRectEdge.top: 55 | border.frame = CGRect.init(x: 0, y: 0, width: frame.width, height: thickness) 56 | break 57 | case UIRectEdge.bottom: 58 | border.frame = CGRect.init(x: 0, y: frame.height - thickness, width: frame.width, height: thickness) 59 | break 60 | case UIRectEdge.left: 61 | border.frame = CGRect.init(x: 0, y: 0, width: thickness, height: frame.height) 62 | break 63 | case UIRectEdge.right: 64 | border.frame = CGRect.init(x: frame.width - thickness, y: 0, width: thickness, height: frame.height) 65 | break 66 | default: 67 | break 68 | } 69 | 70 | border.backgroundColor = color.cgColor; 71 | 72 | self.addSublayer(border) 73 | } 74 | } 75 | ``` -------------------------------------------------------------------------------- /content/how-to-check-for-an-active-internet-connection-on-ios-or-osx.md: -------------------------------------------------------------------------------- 1 | # 如何判断iOS或者OS X的网络状况? 2 | https://stackoverflow.com/questions/1083701/how-to-check-for-an-active-internet-connection-on-ios-or-osx 3 | 4 | ___ 5 | 6 | 首先在项目中引入` SystemConfiguration.framework` 7 | 8 | 导入头文件 9 | 10 | ``` 11 | #import 12 | #import 13 | #import 14 | ``` 15 | 16 | ``` 17 | /* 18 | Connectivity testing code pulled from Apple's Reachability Example: https://developer.apple.com/library/content/samplecode/Reachability 19 | */ 20 | +(BOOL)hasConnectivity { 21 | struct sockaddr_in zeroAddress; 22 | bzero(&zeroAddress, sizeof(zeroAddress)); 23 | zeroAddress.sin_len = sizeof(zeroAddress); 24 | zeroAddress.sin_family = AF_INET; 25 | 26 | SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)&zeroAddress); 27 | if (reachability != NULL) { 28 | //NetworkStatus retVal = NotReachable; 29 | SCNetworkReachabilityFlags flags; 30 | if (SCNetworkReachabilityGetFlags(reachability, &flags)) { 31 | if ((flags & kSCNetworkReachabilityFlagsReachable) == 0) 32 | { 33 | // If target host is not reachable 34 | return NO; 35 | } 36 | 37 | if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0) 38 | { 39 | // If target host is reachable and no connection is required 40 | // then we'll assume (for now) that your on Wi-Fi 41 | return YES; 42 | } 43 | 44 | 45 | if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) || 46 | (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0)) 47 | { 48 | // ... and the connection is on-demand (or on-traffic) if the 49 | // calling application is using the CFSocketStream or higher APIs. 50 | 51 | if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0) 52 | { 53 | // ... and no [user] intervention is needed 54 | return YES; 55 | } 56 | } 57 | 58 | if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN) 59 | { 60 | // ... but WWAN connections are OK if the calling application 61 | // is using the CFNetwork (CFSocketStream?) APIs. 62 | return YES; 63 | } 64 | } 65 | } 66 | 67 | return NO; 68 | } 69 | ``` -------------------------------------------------------------------------------- /content/how-to-check-if-an-nsdate-occurs-between-two-other-nsdates.md: -------------------------------------------------------------------------------- 1 | # 判断一个时间在另外两个时间之间 2 | [How to Check if an NSDate occurs between two other NSDates](https://stackoverflow.com/questions/1072848/how-to-check-if-an-nsdate-occurs-between-two-other-nsdates) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | ```objc 11 | + (BOOL)date:(NSDate*)date isBetweenDate:(NSDate*)beginDate andDate:(NSDate*)endDate 12 | { 13 | // 在开始之间之前 14 | if ([date compare:beginDate] == NSOrderedAscending) 15 | return NO; 16 | 17 | // 在结束时间之后 18 | if ([date compare:endDate] == NSOrderedDescending) 19 | return NO; 20 | 21 | return YES; 22 | } 23 | ``` 24 | 25 | -------------------------------------------------------------------------------- /content/how-to-compare-uicolors.md: -------------------------------------------------------------------------------- 1 | # UIColor进行比较 2 | [How to compare UIColors?](https://stackoverflow.com/questions/970475/how-to-compare-uicolors) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | `isEqual:` 会返回 `NO` 如果比较的两个颜色是不同的类型 (比如 `#FFF` 和 `[UIColor whiteColor]`),所以用下面这方法来比较 11 | 12 | ```objc 13 | - (BOOL)isEqualToColor:(UIColor *)otherColor { 14 | CGColorSpaceRef colorSpaceRGB = CGColorSpaceCreateDeviceRGB(); 15 | 16 | UIColor *(^convertColorToRGBSpace)(UIColor*) = ^(UIColor *color) { 17 | if (CGColorSpaceGetModel(CGColorGetColorSpace(color.CGColor)) == kCGColorSpaceModelMonochrome) { 18 | const CGFloat *oldComponents = CGColorGetComponents(color.CGColor); 19 | CGFloat components[4] = {oldComponents[0], oldComponents[0], oldComponents[0], oldComponents[1]}; 20 | CGColorRef colorRef = CGColorCreate( colorSpaceRGB, components ); 21 | 22 | UIColor *color = [UIColor colorWithCGColor:colorRef]; 23 | CGColorRelease(colorRef); 24 | return color; 25 | } else 26 | return color; 27 | }; 28 | 29 | UIColor *selfColor = convertColorToRGBSpace(self); 30 | otherColor = convertColorToRGBSpace(otherColor); 31 | CGColorSpaceRelease(colorSpaceRGB); 32 | 33 | return [selfColor isEqual:otherColor]; 34 | } 35 | ``` 36 | 37 | -------------------------------------------------------------------------------- /content/how-to-create-an-array-of-selectors.md: -------------------------------------------------------------------------------- 1 | # 创建一个Selectors的数组 2 | [how to create an “array of selectors”](https://stackoverflow.com/questions/2226520/how-to-create-an-array-of-selectors) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 使用C数组 11 | 12 | ```c 13 | static const SEL selectors[] = {@selector(method1), 14 | .... 15 | @selector(method7)}; 16 | 17 | ... 18 | 19 | for (int i = 0; i < sizeof(selectors)/sizeof(selectors[0]); i++) { 20 | [self performSelector:selectors[i]]; 21 | // .... 22 | } 23 | ``` 24 | 25 | > 2 26 | 27 | 存储selector的指针 28 | 29 | ``` 30 | [NSValue valueWithPointer:@selector(x)] 31 | ``` 32 | 33 | ``` 34 | SEL x = (SEL)selectorValue.pointerValue; 35 | ``` 36 | 37 | -------------------------------------------------------------------------------- /content/how-to-embed-small-icon-in-uilabel.md: -------------------------------------------------------------------------------- 1 | # UILabel嵌入小图片 2 | [How to embed small icon in UILabel](https://stackoverflow.com/questions/19318421/how-to-embed-small-icon-in-uilabel) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | **Swift Version** 11 | 12 | ```swift 13 | //Create Attachment 14 | let imageAttachment = NSTextAttachment() 15 | imageAttachment.image = UIImage(named:"iPhoneIcon") 16 | //Set bound to reposition 17 | let imageOffsetY:CGFloat = -5.0; 18 | imageAttachment.bounds = CGRect(x: 0, y: imageOffsetY, width: imageAttachment.image!.size.width, height: imageAttachment.image!.size.height) 19 | //Create string with attachment 20 | let attachmentString = NSAttributedString(attachment: imageAttachment) 21 | //Initialize mutable string 22 | let completeText = NSMutableAttributedString(string: "") 23 | //Add image to mutable string 24 | completeText.append(attachmentString) 25 | //Add your text to mutable string 26 | let textAfterIcon = NSMutableAttributedString(string: "Using attachment.bounds!") 27 | completeText.append(textAfterIcon) 28 | self.mobileLabel.textAlignment = .center; 29 | self.mobileLabel.attributedText = completeText; 30 | ``` 31 | 32 | ------ 33 | 34 | **Objective-C Version** 35 | 36 | ```objc 37 | NSTextAttachment *imageAttachment = [[NSTextAttachment alloc] init]; 38 | imageAttachment.image = [UIImage imageNamed:@"iPhoneIcon"]; 39 | CGFloat imageOffsetY = -5.0; 40 | imageAttachment.bounds = CGRectMake(0, imageOffsetY, imageAttachment.image.size.width, imageAttachment.image.size.height); 41 | NSAttributedString *attachmentString = [NSAttributedString attributedStringWithAttachment:imageAttachment]; 42 | NSMutableAttributedString *completeText= [[NSMutableAttributedString alloc] initWithString:@""]; 43 | [completeText appendAttributedString:attachmentString]; 44 | NSMutableAttributedString *textAfterIcon= [[NSMutableAttributedString alloc] initWithString:@"Using attachment.bounds!"]; 45 | [completeText appendAttributedString:textAfterIcon]; 46 | self.mobileLabel.textAlignment=NSTextAlignmentRight; 47 | self.mobileLabel.attributedText=completeText;] 48 | ``` 49 | 50 | 用 **attachment.bounds**来居中图片 51 | 52 | ![img](/images/08.png) 53 | 54 | -------------------------------------------------------------------------------- /content/how-to-fill-background-image-of-an-uiview.md: -------------------------------------------------------------------------------- 1 | # 背景图片充满UIViw? 2 | [How to fill background image of an UIView](https://stackoverflow.com/questions/8077740/how-to-fill-background-image-of-an-uiview) 3 | 4 | 我有一个UIView,然后设置了一个背景图片 5 | 6 | ```c 7 | self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"sfond-appz.png"]]; 8 | ``` 9 | 10 | 问题在于,背景图片并不是在View中居中,而是重复了几次来填满整个View,是否有方法来填充这个View? 11 | 12 | ___ 13 | 14 | 15 | 16 | > 1 17 | 18 | 你需要先处理一下图片,像下面这样: 19 | 20 | ```c 21 | UIGraphicsBeginImageContext(self.view.frame.size); 22 | [[UIImage imageNamed:@"image.png"] drawInRect:self.view.bounds]; 23 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 24 | UIGraphicsEndImageContext(); 25 | 26 | self.view.backgroundColor = [UIColor colorWithPatternImage:image]; 27 | ``` -------------------------------------------------------------------------------- /content/how-to-get-uitableview-from-uitableviewcell.md: -------------------------------------------------------------------------------- 1 | # 获取UITableViewCell的UITableView 2 | [How to get UITableView from UITableViewCell?](https://stackoverflow.com/questions/15711645/how-to-get-uitableview-from-uitableviewcell) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | ```objc 11 | id view = [tableViewCellInstance superview]; 12 | 13 | while (view && [view isKindOfClass:[UITableView class]] == NO) { 14 | view = [view superview]; 15 | } 16 | 17 | UITableView *tableView = (UITableView *)view; 18 | ``` 19 | > 2 20 | 21 | ```objc 22 | @interface SOUITableViewCell 23 | 24 | @property (weak, nonatomic) UITableView *tableView; 25 | 26 | @end 27 | ``` 28 | 29 | 注意是弱引用,否则会导致循环引用 -------------------------------------------------------------------------------- /content/how-to-hide-uinavigationbar-1px-bottom-line.md: -------------------------------------------------------------------------------- 1 | # 如何隐藏UINavigationBar底部的线? 2 | [How to hide UINavigationBar 1px bottom line](https://stackoverflow.com/questions/19226965/how-to-hide-uinavigationbar-1px-bottom-line) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 以下代码可以有全局效果 11 | 12 | ```objc 13 | [[UINavigationBar appearance] setBackgroundImage:[[UIImage alloc] init] 14 | forBarPosition:UIBarPositionAny 15 | barMetrics:UIBarMetricsDefault]; 16 | 17 | [[UINavigationBar appearance] setShadowImage:[[UIImage alloc] init]]; 18 | ``` 19 | 20 | ![img](/images/05.png) -------------------------------------------------------------------------------- /content/how-to-pass-object-with-nsnotificationcenter.md: -------------------------------------------------------------------------------- 1 | # NSNotificationCenter传递对象 2 | [How to pass object with NSNotificationCenter](https://stackoverflow.com/questions/7896646/how-to-pass-object-with-nsnotificationcenter) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 你可以通过userInfo变量来传递信息,信息包裹在字典里: 11 | 12 | **Class A (发送者):** 13 | 14 | ``` 15 | YourDataObject *message = [[YourDataObject alloc] init]; 16 | // set your message properties 17 | NSDictionary *dict = [NSDictionary dictionaryWithObject:message forKey:@"message"]; 18 | [[NSNotificationCenter defaultCenter] postNotificationName:@"NotificationMessageEvent" object:nil userInfo:dict]; 19 | ``` 20 | 21 | **Class B (接受者):** 22 | 23 | ``` 24 | - (void)viewDidLoad 25 | { 26 | [super viewDidLoad]; 27 | [[NSNotificationCenter defaultCenter] 28 | addObserver:self selector:@selector(triggerAction:) name:@"NotificationMessageEvent" object:nil]; 29 | } 30 | 31 | #pragma mark - Notification 32 | -(void) triggerAction:(NSNotification *) notification 33 | { 34 | NSDictionary *dict = notification.userInfo; 35 | YourDataObject *message = [dict valueForKey:@"message"]; 36 | if (message != nil) { 37 | // do stuff here with your message data 38 | } 39 | } 40 | ``` 41 | 42 | -------------------------------------------------------------------------------- /content/how-to-rotate-a-uiimage-90-degrees.md: -------------------------------------------------------------------------------- 1 | # 旋转图片 2 | [How to Rotate a UIImage 90 degrees?](https://stackoverflow.com/questions/1315251/how-to-rotate-a-uiimage-90-degrees) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | ```objc 11 | static inline double radians (double degrees) {return degrees * M_PI/180;} 12 | UIImage* rotate(UIImage* src, UIImageOrientation orientation) 13 | { 14 | UIGraphicsBeginImageContext(src.size); 15 | 16 | CGContextRef context = UIGraphicsGetCurrentContext(); 17 | 18 | if (orientation == UIImageOrientationRight) { 19 | CGContextRotateCTM (context, radians(90)); 20 | } else if (orientation == UIImageOrientationLeft) { 21 | CGContextRotateCTM (context, radians(-90)); 22 | } else if (orientation == UIImageOrientationDown) { 23 | // NOTHING 24 | } else if (orientation == UIImageOrientationUp) { 25 | CGContextRotateCTM (context, radians(90)); 26 | } 27 | 28 | [src drawAtPoint:CGPointMake(0, 0)]; 29 | 30 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 31 | UIGraphicsEndImageContext(); 32 | return image; 33 | } 34 | ``` -------------------------------------------------------------------------------- /content/how-to-scale-a-uiimageview-proportionally.md: -------------------------------------------------------------------------------- 1 | # UIImageView的伸缩模式 2 | [How to scale a UIImageView proportionally?](https://stackoverflow.com/questions/185652/how-to-scale-a-uiimageview-proportionally) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | ![img](/images/03.png) 11 | 12 | #### ScaletoFill: 13 | 14 | 四面拉伸图片直到四边都填满整个ImageView,这个有可能会导致图片变形 15 | 16 | #### Aspect Fit: 17 | 18 | 拉伸图片直到最大边与View的边相匹配,有可能导致另外一个方向的空余 19 | 20 | #### Aspect Fill: 21 | 22 | 伸缩图片直到最小边与View的边相匹配,有可能导致另外一个方向的超出区域 -------------------------------------------------------------------------------- /content/how-to-set-the-full-width-of-separator-in-uitableview.md: -------------------------------------------------------------------------------- 1 | # UITableView填满分割线 2 | [How to set the full width of separator in UITableView](https://stackoverflow.com/questions/26519248/how-to-set-the-full-width-of-separator-in-uitableview) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | #### Swift: 11 | 12 | ```swift 13 | cell.preservesSuperviewLayoutMargins = false 14 | cell.separatorInset = UIEdgeInsets.zero 15 | cell.layoutMargins = UIEdgeInsets.zero 16 | ``` 17 | 18 | #### Objective-C: 19 | 20 | ```objc 21 | -(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath 22 | { 23 | if ([cell respondsToSelector:@selector(setSeparatorInset:)]) { 24 | [cell setSeparatorInset:UIEdgeInsetsZero]; 25 | } 26 | 27 | if ([cell respondsToSelector:@selector(setLayoutMargins:)]) { 28 | [cell setLayoutMargins:UIEdgeInsetsZero]; 29 | } 30 | } 31 | 32 | -(void)viewDidLayoutSubviews 33 | { 34 | [super viewDidLayoutSubviews]; 35 | if ([self.tableView respondsToSelector:@selector(setSeparatorInset:)]) { 36 | [self.tableView setSeparatorInset:UIEdgeInsetsZero]; 37 | } 38 | 39 | if ([self.tableView respondsToSelector:@selector(setLayoutMargins:)]) { 40 | [self.tableView setLayoutMargins:UIEdgeInsetsZero]; 41 | } 42 | } 43 | ``` -------------------------------------------------------------------------------- /content/how-to-stop-unwanted-uibutton-animation-on-title-change.md: -------------------------------------------------------------------------------- 1 | # 去除UIButton修改标题时的动画效果 2 | 3 | [How to stop unwanted UIButton animation on title change?](https://stackoverflow.com/questions/18946490/how-to-stop-unwanted-uibutton-animation-on-title-change) 4 | 5 | ___ 6 | 7 | 8 | 9 | > 1 10 | 11 | ```objc 12 | [UIView setAnimationsEnabled:NO]; 13 | [_button setTitle:@"title" forState:UIControlStateNormal]; 14 | [UIView setAnimationsEnabled:YES]; 15 | ``` 16 | 17 | 如果是系统的button,你需要在重新启用动画前调用 18 | 19 | ```objc 20 | [_button layoutIfNeeded]; 21 | ``` 22 | 23 | > 2 24 | 25 | ```objc 26 | [UIView performWithoutAnimation:^{ 27 | [self.myButton setTitle:text forState:UIControlStateNormal]; 28 | [self.myButton layoutIfNeeded]; 29 | }]; 30 | ``` -------------------------------------------------------------------------------- /content/how-to-store-custom-objects-in-nsuserdefaults.md: -------------------------------------------------------------------------------- 1 | # 如何在NSUserDefaults里保存一个自定义对象? 2 | [How to store custom objects in NSUserDefaults](https://stackoverflow.com/questions/2315948/how-to-store-custom-objects-in-nsuserdefaults) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 你需要实现NSCopying协议并实现以下方法 11 | 12 | ```objc 13 | - (void)encodeWithCoder:(NSCoder *)encoder { 14 | //Encode properties, other class variables, etc 15 | [encoder encodeObject:self.question forKey:@"question"]; 16 | [encoder encodeObject:self.categoryName forKey:@"category"]; 17 | [encoder encodeObject:self.subCategoryName forKey:@"subcategory"]; 18 | } 19 | 20 | - (id)initWithCoder:(NSCoder *)decoder { 21 | if((self = [super init])) { 22 | //decode properties, other class vars 23 | self.question = [decoder decodeObjectForKey:@"question"]; 24 | self.categoryName = [decoder decodeObjectForKey:@"category"]; 25 | self.subCategoryName = [decoder decodeObjectForKey:@"subcategory"]; 26 | } 27 | return self; 28 | } 29 | ``` 30 | 31 | 在`NSUserDefaults`读写: 32 | 33 | ```objc 34 | - (void)saveCustomObject:(MyObject *)object key:(NSString *)key { 35 | NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:object]; 36 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 37 | [defaults setObject:encodedObject forKey:key]; 38 | [defaults synchronize]; 39 | 40 | } 41 | 42 | - (MyObject *)loadCustomObjectWithKey:(NSString *)key { 43 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 44 | NSData *encodedObject = [defaults objectForKey:key]; 45 | MyObject *object = [NSKeyedUnarchiver unarchiveObjectWithData:encodedObject]; 46 | return object; 47 | } 48 | ``` -------------------------------------------------------------------------------- /content/how-to-swizzle-a-class-method-on-ios.md: -------------------------------------------------------------------------------- 1 | # Swizzle 类方法 2 | [How to swizzle a class method on iOS?](https://stackoverflow.com/questions/3267506/how-to-swizzle-a-class-method-on-ios) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 这是实例方法的swizzle: 11 | 12 | ```objc 13 | static void SwizzleMethod(Class cls, SEL ori, SEL rep) { 14 | Method oriMethod = class_getInstanceMethod(cls, ori); 15 | Method repMethod = class_getInstanceMethod(cls, rep); 16 | 17 | BOOL flag = class_addMethod(cls, ori, method_getImplementation(repMethod), method_getTypeEncoding(repMethod)); 18 | 19 | if (flag) { 20 | class_replaceMethod(cls, rep, method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod)); 21 | } else { 22 | method_exchangeImplementations(oriMethod, repMethod); 23 | } 24 | } 25 | ``` 26 | 27 | Class还有一个用来获取类方法的`class_getClassMethod`, 28 | 29 | 所以如果是要swizzle类方法的话,将`class_getInstanceMethod`换成`class_getClassMethod`即可,也就是 30 | 31 | ```objc 32 | static void SwizzleMethod(Class cls, SEL ori, SEL rep) { 33 | Method oriMethod = class_getClassMethod(cls, ori); 34 | Method repMethod = class_getClassMethod(cls, rep); 35 | 36 | BOOL flag = class_addMethod(cls, ori, method_getImplementation(repMethod), method_getTypeEncoding(repMethod)); 37 | 38 | if (flag) { 39 | class_replaceMethod(cls, rep, method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod)); 40 | } else { 41 | method_exchangeImplementations(oriMethod, repMethod); 42 | } 43 | } 44 | ``` 45 | 46 | 但是,我们再来看看`class_getClassMethod`的源码 47 | 48 | ```objc 49 | Method class_getClassMethod(Class cls, SEL sel) 50 | { 51 | if (!cls || !sel) return nil; 52 | 53 | return class_getInstanceMethod(cls->getMeta(), sel); 54 | } 55 | ``` 56 | 57 | 实际上还是调用的`class_getInstanceMethod`,只是这个类变成了元类 58 | 59 | 所以,用`class_getInstanceMethod`也可以获取到类方法,在调用swizzlingMethod时,传入元类; 60 | 61 | ```objc 62 | SwizzleMethod(object_getClass([Foo class]), @selector(bar), @selector(swz_bar)); 63 | ``` 64 | 65 | -------------------------------------------------------------------------------- /content/how-to-tell-if-uiviewcontrollers-view-is-visible.md: -------------------------------------------------------------------------------- 1 | # 如何判断UIViewController的View是否可见 2 | [How to tell if UIViewController's view is visible](https://stackoverflow.com/questions/2777438/how-to-tell-if-uiviewcontrollers-view-is-visible) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | View的 [window property](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/UIView/UIView.html#//apple_ref/doc/uid/TP40006816-CH3-SW55) 非空则表示这个View可见。 11 | 12 | 另外,调用View的方法会导致View进行Load(如果之前没有load的话),这是没有必要的而且可能会导致未知情况,所以最好在调用方法之前先确认一下是否已经被load了 13 | 14 | #### Objective-C: 15 | 16 | ``` 17 | if (viewController.isViewLoaded && viewController.view.window) { 18 | // viewController is visible 19 | } 20 | ``` 21 | 22 | 如果你有一个UINavigationController来管理view controllers, 那你应该通过检测这个 [visibleViewController](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UINavigationController_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40006934-CH3-SW1) 属性. 23 | 24 | #### Swift 25 | 26 | ``` 27 | if viewController.viewIfLoaded?.window != nil { 28 | // viewController is visible 29 | } 30 | ``` -------------------------------------------------------------------------------- /content/how-to-use-nscache.md: -------------------------------------------------------------------------------- 1 | # 如何使用NSCache? 2 | [How to use NSCache](https://stackoverflow.com/questions/5755902/how-to-use-nscache) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 你可以像使用 `NSMutableDictionary`一样使用`NSCache` . 不同的是当`NSCache` 内存超出压力 (比如缓存了太多) 它会释放一些值来保留空间。 11 | 12 | 如果你可以重建这些值 (通过互联网下载, 计算, 其他方式) ,那么 `NSCache` 可能适合你. 但是如果数据不可复现 (比如用户输入,数据对时间敏感) ,那你不应该存在 `NSCache` 因为这些数据有可能会被消失。 13 | 14 | ```objc 15 | // 你的缓存应该具有超出某个方法的生命周期,可以伴随着application,delegate或者Viewcontroller. 16 | NSCache *myCache = ...; 17 | NSAssert(myCache != nil, @"cache object is missing"); 18 | 19 | // 从缓存里获取,如果存在的话 20 | Widget *myWidget = [myCache objectForKey: @"Important Widget"]; 21 | if (!myWidget) { 22 | // 有可能没有放入缓存,或者已经被移除了,那么就应该重新建立 23 | myWidget = [[[Widget alloc] initExpensively]]; 24 | 25 | // 放入缓存中 26 | [myCache setObject: myWidget forKey: @"Important Widget"]; 27 | } 28 | 29 | // 这样无论如何myWidget都是有的 30 | if (myWidget) { 31 | [myWidget runOrWhatever]; 32 | } 33 | ``` -------------------------------------------------------------------------------- /content/ios-app-programmatically-get-build-version.md: -------------------------------------------------------------------------------- 1 | # 获取APP的版本信息 2 | [iOS app, programmatically get build version](https://stackoverflow.com/questions/16888780/ios-app-programmatically-get-build-version) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | "Version"号 : 11 | 12 | Swift 3 13 | 14 | ```swift 15 | let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String 16 | ``` 17 | 18 | ObjC 19 | 20 | ```Objc 21 | NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]; 22 | ``` 23 | 24 | "Build"号: 25 | 26 | Swift 3 27 | 28 | ```swift 29 | let build = Bundle.main.infoDictionary?[kCFBundleVersionKey as String] as? String 30 | ``` 31 | 32 | ObjC 33 | 34 | ```ojbc 35 | NSString *build = [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleVersionKey]; 36 | ``` 37 | 38 | -------------------------------------------------------------------------------- /content/iphone-sdk-what-is-the-difference-between-loadview-and-viewdidload.md: -------------------------------------------------------------------------------- 1 | # loadView和viewDidLoad 2 | [iPhone SDK: what is the difference between loadView and viewDidLoad?](https://stackoverflow.com/questions/573958/iphone-sdk-what-is-the-difference-between-loadview-and-viewdidload) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | #### loadView 11 | 12 | `loadView` 是 `UIViewController` 的一个方法用来加载View和给 `view` 属性赋值。This is also the location that `UIViewController` 的子类同样适用,如果你想要自己给 `view` 属性赋值就重写这个方法. 13 | 14 | !!!不要在这个方法里去使用getter,self.view的方式去获取View。这会导致崩溃。 15 | 16 | loadView如果不实现则不调用 17 | 18 | #### ViewDidLoad 19 | 20 | `viewDidLoad` 这个方法是在View被加载成功后调用. 这个会被调用在loadView调用之后。 -------------------------------------------------------------------------------- /content/is-autoreleasepool-still-required-for-modern-ios-8-nsoperation-usage.md: -------------------------------------------------------------------------------- 1 | # NSOperation或者GCD编程是否需要autoreleasepool? 2 | [Is @autoreleasepool still required for modern iOS 8 NSOperation usage?](https://stackoverflow.com/questions/24562043/is-autoreleasepool-still-required-for-modern-ios-8-nsoperation-usage) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 如果你正在使用 `NSOperation` 并且声明了 `main` 方法, 不需要去创建一个autoreleasepool. `start` 方法会默认 pushes一个 `NSAutoReleasePool`, 调用 `main` 随后会 pops `NSAutoReleasePool`. `NSInvocationOperation` 和 `NSBlockOperation`也一样, `start` 方法的声明是一样的. 11 | 12 | 下面是 `NSOperation`的 `start` 方法的一些操作,注意调用了 NSPushAutoreleasePool, 随后调用main 方法,接着调用NSPopAutoreleasePool: 13 | 14 | ```Objc 15 | Foundation`-[newMyObj__NSOperationInternal _start:]: 16 | 0x7fff8e5df30f: pushq %rbp 17 | 18 | ... 19 | 20 | 0x7fff8e5df49c: callq *-0x16b95bb2(%rip) ; (void *)0x00007fff8d9d30c0: objc_msgSend 21 | 0x7fff8e5df4a2: movl $0x1, %edi 22 | 23 | ; new NSAutoreleasePool is pushed here 24 | 0x7fff8e5df4a7: callq 0x7fff8e5df6d6 ; NSPushAutoreleasePool 25 | 26 | ... NSOperation main is called 27 | 28 | 0x7fff8e5df6a4: callq *-0x16b95dba(%rip) ; (void *)0x00007fff8d9d30c0: objc_msgSend 29 | 0x7fff8e5df6aa: movq %r15, %rdi 30 | 31 | ; new NSAutoreleasePool is popped here, which releases any objects added in the main method 32 | 0x7fff8e5df6ad: callq 0x7fff8e5e1408 ; NSPopAutoreleasePool 33 | ``` 34 | 35 | ![img](/images/15.png) 36 | 37 | ```objc 38 | #import 39 | 40 | @interface MyObj : NSObject 41 | @end 42 | 43 | @implementation MyObj 44 | 45 | - (void)dealloc { 46 | NSLog(@"dealloc"); 47 | } 48 | 49 | @end 50 | 51 | @interface TestOp : NSOperation { 52 | MyObj *obj; 53 | } 54 | 55 | @end 56 | 57 | @implementation TestOp 58 | 59 | - (MyObj *)setMyObj:(MyObj *)o { 60 | MyObj *old = obj; 61 | obj = o; 62 | return old; 63 | } 64 | 65 | - (void)main { 66 | MyObj *old = [self setMyObj:[MyObj new]]; 67 | [self setMyObj:old]; 68 | } 69 | 70 | @end 71 | 72 | int main(int argc, const char * argv[]) { 73 | @autoreleasepool { 74 | // insert code here... 75 | NSLog(@"Hello, World!"); 76 | 77 | NSOperationQueue *q = [NSOperationQueue new]; 78 | TestOp *op = [TestOp new]; 79 | [q addOperation:op]; 80 | 81 | [op waitUntilFinished]; 82 | } 83 | return 0; 84 | } 85 | ``` 86 | 87 | GCD也有类似的管理[Concurrency Programming Guide](https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html#//apple_ref/doc/uid/TP40008091-CH102-SW17): 88 | 89 | 如果您的Block创建了多个Objective-C对象,则可能需要将block的部分代码放在@autorelease块中,以处理这些对象的内存管理。虽然GCD调度队列有他们自己的autorelease池,他们不保证什么时候这些池被drained。如果您的应用程序受到内存限制,创建您自己的自动释放池允许您以更有规律的间隔释放自动释放对象的内存。 90 | 91 | -------------------------------------------------------------------------------- /content/make-autolayout.md: -------------------------------------------------------------------------------- 1 | # 使用自动布局? 2 | ___ 3 | 4 | 5 | 6 | > 1 7 | 8 | ```objective-c 9 | customView.translatesAutoresizingMaskIntoConstraints = NO; 10 | NSLayoutConstraint *topConstraint = 11 | [NSLayoutConstraint constraintWithItem:customView 12 | attribute:NSLayoutAttributeTop 13 | relatedBy:NSLayoutRelationEqual 14 | toItem:self.view 15 | attribute:NSLayoutAttributeTop 16 | multiplier:1.f 17 | constant:0.f]; 18 | 19 | NSLayoutConstraint *rightConstraint = 20 | [NSLayoutConstraint constraintWithItem:customView 21 | attribute:NSLayoutAttributeRight 22 | relatedBy:NSLayoutRelationEqual 23 | toItem:self.view 24 | attribute:NSLayoutAttributeRight 25 | multiplier:1.f 26 | constant:0.f]; 27 | 28 | NSLayoutConstraint *leftConstraint = 29 | [NSLayoutConstraint constraintWithItem:customView 30 | attribute:NSLayoutAttributeLeft 31 | relatedBy:NSLayoutRelationEqual 32 | toItem:self.view 33 | attribute:NSLayoutAttributeLeft 34 | multiplier:1.f 35 | constant:0.f]; 36 | 37 | NSLayoutConstraint *bottomConstraint = 38 | [NSLayoutConstraint constraintWithItem:customView 39 | attribute:NSLayoutAttributeBottom 40 | relatedBy:NSLayoutRelationEqual 41 | toItem:self.view 42 | attribute:NSLayoutAttributeBottom 43 | multiplier:1.f 44 | constant:0.f]; 45 | 46 | [self.view addConstraint:topConstraint]; 47 | [self.view addConstraint:rightConstraint]; 48 | [self.view addConstraint:leftConstraint]; 49 | [self.view addConstraint:bottomConstraint]; 50 | 51 | ``` -------------------------------------------------------------------------------- /content/nsobject-load-and-initialize-what-do-they-do.md: -------------------------------------------------------------------------------- 1 | # NSobject的+load +initialize做了什么? 2 | [NSObject +load and +initialize - What do they do?](https://stackoverflow.com/questions/13326435/nsobject-load-and-initialize-what-do-they-do) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | #### The `load` message 11 | 12 | 在类对象被加载入进程的的地址空间内之后很快,运行时发送load消息到每一个类对象。如果类是程序执行文件的一部分,运行时在进程生命周期很早的时候就发送了load消息。如果类在一个静态加载库中,运行时会在静态库被加载入进程的地址空间内发送load消息。 13 | 14 | 此外,只有当类实现了load方法,运行时才会发送load消息给类对象,例如 15 | 16 | ```Objc 17 | @interface Superclass : NSObject 18 | @end 19 | 20 | @interface Subclass : Superclass 21 | @end 22 | 23 | @implementation Superclass 24 | 25 | + (void)load { 26 | NSLog(@"in Superclass load"); 27 | } 28 | 29 | @end 30 | 31 | @implementation Subclass 32 | 33 | // ... load not implemented in this class 34 | 35 | @end 36 | ``` 37 | 38 | 运行时会发送 `load` 消息给 `Superclass` .不会发送 `load` 消息给 `Subclass` 对象,尽管`Subclass` 继承自 `Superclass`. 39 | 40 | 运行时会在一个类的所有父类已经发送load消息之后(如果父类有声明load方法),才发送load消息给这个类,但是你无法知道这些类是否已经收到了load消息。 41 | 42 | 每个加载进进程地址空间的的类(声明了load方法)都会收到load消息,不管这个类是否有被用到 43 | 44 | 可以看看运行时如何查看`load` 在 `_class_getLoadMethod` of [`objc-runtime-new.mm`](http://opensource.apple.com/source/objc4/objc4-532.2/runtime/objc-runtime-new.mm), 直接调用 `call_class_loads`in [`objc-loadmethod.mm`](http://opensource.apple.com/source/objc4/objc4-532.2/runtime/objc-loadmethod.mm). 45 | 46 | 当运行时加载category是,也会运行load方法。如果两个category声明了同样的方法,其中一个会胜出并且被使用,另外一个永远不会被调用 47 | 48 | #### The `initialize` Method 49 | 50 | 运行时会调用 `initialize` 方法在发送其他所有消息之前(除了load方法),消息发送用的是寻常机制,所以如果你的类没有声明 `initialize` ,但是父类有声明,那么这个类会用父类的 `initialize` 。 51 | 52 | 运行时首先会发送 `initialize` 给这个类的所有父类。 53 | 54 | ```objc 55 | @interface Superclass : NSObject 56 | @end 57 | 58 | @interface Subclass : Superclass 59 | @end 60 | 61 | @implementation Superclass 62 | 63 | + (void)initialize { 64 | NSLog(@"in Superclass initialize; self = %@", self); 65 | } 66 | 67 | @end 68 | 69 | @implementation Subclass 70 | 71 | // ... initialize not implemented in this class 72 | 73 | @end 74 | 75 | int main(int argc, char *argv[]) { 76 | @autoreleasepool { 77 | Subclass *object = [[Subclass alloc] init]; 78 | } 79 | return 0; 80 | } 81 | ``` 82 | 83 | ``` 84 | 2012-11-10 16:18:38.984 testApp[7498:c07] in Superclass initialize; self = Superclass 85 | 2012-11-10 16:18:38.987 testApp[7498:c07] in Superclass initialize; self = Subclass 86 | ``` 87 | 88 | 权威的声明方式应该是这样 89 | 90 | ```objc 91 | @implementation Someclass 92 | 93 | + (void)initialize { 94 | if (self == [Someclass class]) { 95 | // do whatever 96 | } 97 | } 98 | ``` 99 | 100 | 这种方式的重点在于,可以避免Someclass重复initialize它自己,当它的其中一个子类没有声明 `initialize` 101 | 102 | 运行时发送 `initialize` 消息在 `_class_initialize` [`objc-initialize.mm`](http://opensource.apple.com/source/objc4/objc4-532.2/runtime/objc-initialize.mm). -------------------------------------------------------------------------------- /content/nsoperation-vs-grand-central-dispatch.md: -------------------------------------------------------------------------------- 1 | # NSOperation vs. GCD? 2 | [NSOperation vs Grand Central Dispatch](https://stackoverflow.com/questions/10373331/nsoperation-vs-grand-central-dispatch) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | `GCD` 是更底层 API. 11 | `NSOperation` 和 `NSOperationQueue` 是 Objective-C 类. 12 | `NSOperationQueue` 基于`GCD`. 如果你在用NSOperation, 那你是隐式使用 *Grand Central Dispatch.* 13 | 14 | **GCD 相比 NSOperation的优势:** 15 | *i. implementation* 16 | `GCD` 的声明很轻量 17 | `NSOperationQueue` 复杂和重量级 18 | 19 | *ii. 效率* 20 | 21 | 当使用NSOperations和NSOperationQueues时,会有一些不必要的开销。 这些是Cocoa对象,他们需要分配和释放。 22 | 23 | **NSOperation 相比 GCD的优势:** 24 | 25 | *i. Operation控制* 26 | 你可以暂停(Pause), 取消(Cancel), 恢复(Resume) 一个 `NSOperation` 27 | 28 | *ii. 依赖* 29 | 你可以在两个 `NSOperations`之间建立依赖 30 | operation 不会开始直到它的依赖已经完成了. 31 | 32 | *iii. Operation状态* 33 | 可以监听operation的状态. 就绪(ready) ,执行中(executing)和完成(finished) 34 | 35 | *iv. Operation最大数* 36 | 你可以指定 operations同时操作的数量 37 | 38 | **什么时候用 GCD or NSOperation** 39 | 如果你想对Queue有更多的操作,你应该使用 `NSOperation` 40 | 41 | 如你想要轻量方便地使用,就应该用 `GCD` -------------------------------------------------------------------------------- /content/nsstring-property-copy-or-retain.md: -------------------------------------------------------------------------------- 1 | # NSString的属性修饰符应该用copy还是strong(retain)? 2 | [NSString property: copy or retain?](https://stackoverflow.com/questions/387959/nsstring-property-copy-or-retain) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | #### 对于NSString,用copy修饰是不是比用retain修饰好? 11 | 12 | 是的,一般情况总是用copy修饰符 13 | 14 | 这是因为**NSString property**可能被**NSString**实例或者**NSMutableString**实例赋值, 所以我们没有办法确认传过来的对象是可变的还是不可变的 15 | 16 | #### copy修饰属性是否比用retain修饰更低效? 17 | 18 | - 如果你的属性被赋值传过来的是 **NSString实例**, 答案是 "**No**" - copy没有更低效(没有更低效的原因是不可变对象的copy依旧是浅拷贝). 19 | - 如果你的属性被赋值而传过来的对象是 **NSMutableString实例对象**,那么答案就是 "**Yes**" - copying比retain更低效.(因为可变对象的复制时深拷贝) 20 | 21 | #### 什么情况下使用copy? 22 | 23 | 你应该使用copy,当你不想属性的内部状态在毫无提示的情况下被更改(当传递的是可变对象,如果可变对象做了更改,那么这个属性也会跟着修改)。 24 | 25 | #### 深拷贝,浅拷贝 26 | 27 | - [immutableObject copy] // 浅复制 28 | - [immutableObject mutableCopy] //深复制 29 | - [mutableObject copy] //深复制 30 | - [mutableObject mutableCopy] //深复制 31 | 32 | -------------------------------------------------------------------------------- /content/number-of-days-between-two-nsdates.md: -------------------------------------------------------------------------------- 1 | # 计算两个NSDate之间的天数? 2 | [Number of days between two NSDates](https://stackoverflow.com/questions/4739483/number-of-days-between-two-nsdates) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | #### Objective-C: 11 | 12 | ```objc 13 | + (NSInteger)daysBetweenDate:(NSDate*)fromDateTime andDate:(NSDate*)toDateTime 14 | { 15 | NSDate *fromDate; 16 | NSDate *toDate; 17 | 18 | NSCalendar *calendar = [NSCalendar currentCalendar]; 19 | 20 | [calendar rangeOfUnit:NSCalendarUnitDay startDate:&fromDate 21 | interval:NULL forDate:fromDateTime]; 22 | [calendar rangeOfUnit:NSCalendarUnitDay startDate:&toDate 23 | interval:NULL forDate:toDateTime]; 24 | 25 | NSDateComponents *difference = [calendar components:NSCalendarUnitDay 26 | fromDate:fromDate toDate:toDate options:0]; 27 | 28 | return [difference day]; 29 | } 30 | ``` 31 | 32 | #### Swift: 33 | 34 | ```swift 35 | extension NSDate { 36 | func numberOfDaysUntilDateTime(toDateTime: NSDate, inTimeZone timeZone: NSTimeZone? = nil) -> Int { 37 | let calendar = NSCalendar.currentCalendar() 38 | if let timeZone = timeZone { 39 | calendar.timeZone = timeZone 40 | } 41 | 42 | var fromDate: NSDate?, toDate: NSDate? 43 | 44 | calendar.rangeOfUnit(.Day, startDate: &fromDate, interval: nil, forDate: self) 45 | calendar.rangeOfUnit(.Day, startDate: &toDate, interval: nil, forDate: toDateTime) 46 | 47 | let difference = calendar.components(.Day, fromDate: fromDate!, toDate: toDate!, options: []) 48 | return difference.day 49 | } 50 | } 51 | ``` 52 | 53 | -------------------------------------------------------------------------------- /content/objective-c-assertion-vs-exception-vs-error.md: -------------------------------------------------------------------------------- 1 | # Assertion vs. Exception vs. Error 2 | [Objective-C: Assertion vs. Exception vs. Error](https://stackoverflow.com/questions/5009597/objective-c-assertion-vs-exception-vs-error) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | ``` 11 | #define NSAssert(condition, desc, ...) 12 | ``` 13 | 14 | NSAssert(断言)是一个宏定义,它会抛出一个Exception异常当condition条件不成立时,所以NSAssert很简短方便地去确认代码里的一个假设。 15 | 16 | NSException是一个可以自定义的异常,你可以`@throw`一个异常使运行停止,你也可以`@catch`一个异常,使得代码可以继续运行。 17 | 18 | NSError应该在你的交互有错误而不是编程错误时使用,这个错误是可以被修复的,你可以在里面存放错误代码,错误信息。 19 | 20 | -------------------------------------------------------------------------------- /content/objective-c-declared-property-attributes-nonatomic-copy-strong-weak.md: -------------------------------------------------------------------------------- 1 | # Objective-C属性修饰符(nonatomic, copy, strong, weak)? 2 | [Objective-C declared @property attributes (nonatomic, copy, strong, weak)](https://stackoverflow.com/questions/9859719/objective-c-declared-property-attributes-nonatomic-copy-strong-weak) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | **Nonatomic** 11 | 12 | `nonatomic` 被用于多线程编程.如果我们在声明时用nonatomic修饰属性, 那么在多线程的时候,其他线程也可以同时访问该属性. 13 | 14 | **Copy** 15 | 16 | `copy` 在可变对象的时候需要. 你不希望你的对象的改变会被其他可变对象所影响,在用完之后会被释放. 17 | 18 | **Assign** 19 | 20 | `Assign` 与 `copy`.相反,当你访问 `assign` 属性, 会直接返回一个真实值. 一般你在使用基础值类型 (float, int, BOOL...) 21 | 22 | **Retain** 23 | 24 | `retain` 被用在当一个指针指向一个对象. setter方法被 `@synthesize` 将 retain (引用计数加一) 这个对象. 当你用完这个对象你需要释放它. 用retain将会使对象的引用计数加一 25 | 26 | **Strong** 27 | 28 | `strong` 是 Automated Reference Counting (ARC).用来替换retain的. 29 | 30 | **Weak** 31 | 32 | `weak` 与 `strong` 类似,用于指针对象,但是不会使引用计数加1.它不会成为对象的所有者,只是与对象保持一份引用关系.如果对象的引用计数归为0,即使有weak指针指向它,依旧会被dealloc。 33 | 34 | 当weak指针指向的对象被dealloc时,weak指针会被置为nil. -------------------------------------------------------------------------------- /content/objective-c-pass-block-as-parameter.md: -------------------------------------------------------------------------------- 1 | # Block作为参数传递 2 | [Objective-C pass block as parameter](https://stackoverflow.com/questions/7936570/objective-c-pass-block-as-parameter) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | block变量取决于它的参数和返回值,一般情况下,block声明和函数声明差不多。把 `*` 换成 `^`: 11 | 12 | ``` 13 | - (void)iterateWidgets:(void (^)(id, int))iteratorBlock; 14 | ``` 15 | 16 | 这种看起来有点乱,你可以先进行声明 17 | 18 | ``` 19 | typedef void (^ IteratorBlock)(id, int); 20 | ``` 21 | 22 | ``` 23 | - (void)iterateWidgets:(IteratorBlock)iteratorBlock; 24 | ``` -------------------------------------------------------------------------------- /content/push-viewcontroller-slow.md: -------------------------------------------------------------------------------- 1 | # UINavigationController在pushViewController时卡顿? 2 | ___ 3 | 4 | 5 | 6 | > 1 7 | 8 | 进行开发中,遇到了个小问题: 9 | 10 | 在使用UINavigationController的-pushViewController:animated:执行入栈一个子控制器操作时(即最新栈顶子控制器),会出现推出(即入栈)"卡顿"现象, 11 | 12 | 原因:这是因为从iOS7开始, UIViewController的根view的背景颜色默认为透明色(即clearColor),所谓"卡顿"其实就是由于透明色重叠后,造成视觉上的错觉,所以这并不是真正的"卡顿",但这种"卡顿"现象还是让人觉得极其不舒服的,还是务必得解决的! 13 | 14 | 解决方法:只要在该UINavigationController所push的那个子控制器C(C即当前最新栈顶子控制器)中赋值其根view的背景颜色为某种颜色,即取缔默认的透明色 (即clearColor),就能解决所谓的"卡顿"问题啦! 15 | 16 | self.view.backgroundColor = [UIColor whiteColor]; -------------------------------------------------------------------------------- /content/send-post-request-using-nsurlsession.md: -------------------------------------------------------------------------------- 1 | # 用NSURLSession发送一个POST请求 2 | [Send POST request using NSURLSession](https://stackoverflow.com/questions/19099448/send-post-request-using-nsurlsession) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 你可以用NSDictionary包装一下参数,下面的代码可以发送这些参数到一个JSON Server 11 | 12 | ```objc 13 | NSError *error; 14 | 15 | NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; 16 | NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil]; 17 | NSURL *url = [NSURL URLWithString:@"[JSON SERVER"]; 18 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url 19 | cachePolicy:NSURLRequestUseProtocolCachePolicy 20 | timeoutInterval:60.0]; 21 | 22 | [request addValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; 23 | [request addValue:@"application/json" forHTTPHeaderField:@"Accept"]; 24 | 25 | [request setHTTPMethod:@"POST"]; 26 | NSDictionary *mapData = [[NSDictionary alloc] initWithObjectsAndKeys: @"TEST IOS", @"name", 27 | @"IOS TYPE", @"typemap", 28 | nil]; 29 | NSData *postData = [NSJSONSerialization dataWithJSONObject:mapData options:0 error:&error]; 30 | [request setHTTPBody:postData]; 31 | 32 | 33 | NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 34 | 35 | }]; 36 | 37 | [postDataTask resume]; 38 | ``` -------------------------------------------------------------------------------- /content/some-questions.md: -------------------------------------------------------------------------------- 1 | # 总结几个知识点 2 | ___ 3 | 4 | 5 | 6 | > 一、第三方统计上传的策略 7 | 8 | **友盟** 9 | 10 | 1. 启动时发送:默认 11 | 2. 按间隔发送:按特定间隔发送数据,间隔时长介于90秒与1天之间。 12 | 13 | **腾讯**: 14 | 15 | 1. 实时发送; 16 | 17 | 2. 启动时发送; 18 | 3. 数量发送:默认当消息数量达到30条时发送一次。 19 | 4. Wifi发送:只在wifi状态下发送,非wifi情况缓存到本地。 20 | 5. 间隔发送:间隔一段时间发送,每隔一段时间一次性发送到服务器。 21 | 22 | > 二、弱网优化 23 | 24 | - 减小数据包大小和优化包量:压缩、精简包头、消息合并等方式,来减小数据包大小和包量。 25 | - DNS查询优化:根据客户端IP和服务器接入点IP,返回最优的接入点列表,包括IP的排序,以及客户端接入的国家、省份、运营商、APN和网关。 26 | - 控制数据包大小不超过1500,避免分片 27 | - 优化TCP socket参数,包括:是否关闭快速回收、初始RTO、初始拥塞窗口、socket缓存大小、Delay-ACK、Selective-ACK、TCP_CORK、拥塞算法。 28 | - 复用连接 29 | 30 | > 三、启动优化 31 | 32 | 1、为什么合并第三方库可以加载更快? 33 | 34 | dylib loading载入动态库阶段,这个过程中,会去装载app使用的动态库,而每一个动态库有它自己的依赖关系,所以会消耗时间去查找和读取。对于Apple提供的的系统动态库,做了高度的优化。而对于开发者定义导入的动态库,则需要在花费更多的时间。Apple官方建议尽量少的使用自定义的动态库,或者考虑合并动态库。 35 | 36 | 2、延迟初始化的策略? 37 | 38 | 答:建一个类来管理初始化,所有需要初始化的代码都在这里进行,分类初始化: 39 | 40 | 1)、日志 / 统计等需要第一时间启动的, 仍然伴随 didFinishLaunchingWithOptions 启动. 41 | 42 | 2)、用户数据需要在广告显示完成以后使用, 所以需要伴随广告页启动。 43 | 44 | 3)、比如分享业务, 肯定是用户能看到真正的主界面以后才需要启动, 所以推迟到主界面加载完成以后启动, 只需要将代码放到方法里。 45 | 46 | > 四、ARC MRC下Block的区别 47 | 48 | Block有三种Block:NSConcreteGlobalBlock, NSConcreteStackBlock,NSConcreteMallocBlock 49 | 50 | - MRC情况:需要手动copy到堆中,也就是NSConcreteStackBlock> NSConcreteMallocBlock 51 | - ARC情况:copy修饰NSConcreteStackBlock,会自动NSConcreteStackBlock> NSConcreteMallocBlock,也就是说,ARC下Block实际使用时只有NSConcreteGlobalBlock,NSConcreteMallocBlock两种 52 | 53 | -------------------------------------------------------------------------------- /content/synthesize-vs-dynamic-what-are-the-differences.md: -------------------------------------------------------------------------------- 1 | # @synthesize vs @dynamic? 2 | [@synthesize vs @dynamic, what are the differences?](https://stackoverflow.com/questions/1160498/synthesize-vs-dynamic-what-are-the-differences) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | @synthesize 会自动给property属性自动生成getter方法和setter方法 . 11 | 12 | @dynamic 只是告诉编译器getter和setter方法不是由Class本身来声明,而是在其他地方生成(父类或者在runtime的时候生成) 13 | 14 | 如果在 `NSManagedObject` (CoreData)你想要创建一个属性的话。需要使用@dynamic。 -------------------------------------------------------------------------------- /content/the-best-way-to-remove-duplicate-values-from-nsmutablearray-in-objective-c.md: -------------------------------------------------------------------------------- 1 | # 数组去重 2 | [The best way to remove duplicate values from NSMutableArray in Objective-C?](https://stackoverflow.com/questions/1025674/the-best-way-to-remove-duplicate-values-from-nsmutablearray-in-objective-c) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 如果不用考虑顺序的话,用NSSet 11 | 12 | ``` 13 | NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourArray]; 14 | NSArray *arrayWithoutDuplicates = [orderedSet array]; 15 | ``` 16 | 17 | > 2 18 | 19 | 用 [Object Operators from Key Value Coding](http://nshipster.com/kvc-collection-operators/) 20 | 21 | ``` 22 | uniquearray = [yourarray valueForKeyPath:@"@distinctUnionOfObjects.self"]; 23 | ``` -------------------------------------------------------------------------------- /content/try-catch-block-in-objective-c.md: -------------------------------------------------------------------------------- 1 | # @try - catch block 2 | [@try - catch block in Objective-c](https://stackoverflow.com/questions/3363612/try-catch-block-in-objective-c) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | ```objc 11 | NSString *test = @"test"; 12 | unichar a; 13 | int index = 5; 14 | 15 | @try { 16 | a = [test characterAtIndex:index]; 17 | } 18 | @catch (NSException *exception) { 19 | NSLog(@"%@", exception.reason); 20 | } 21 | @finally { 22 | NSLog(@"Char at index %d cannot be found", index); 23 | NSLog(@"Max index is: %d", [test length]-1); 24 | } 25 | ``` 26 | 27 | Log: 28 | 29 | > [__NSCFConstantString characterAtIndex:]: Range or index out of bounds 30 | > 31 | > Char at index 5 cannot be found 32 | > 33 | > Max index is: 3 -------------------------------------------------------------------------------- /content/types-in-objective-c-on-iphone.md: -------------------------------------------------------------------------------- 1 | # Objective-C里类型大小 2 | [Types in objective-c on iPhone](https://stackoverflow.com/questions/2107544/types-in-objective-c-on-iphone) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | ``` 11 | NSLog(@"Primitive sizes:"); 12 | NSLog(@"The size of a char is: %d.", sizeof(char)); 13 | NSLog(@"The size of short is: %d.", sizeof(short)); 14 | NSLog(@"The size of int is: %d.", sizeof(int)); 15 | NSLog(@"The size of long is: %d.", sizeof(long)); 16 | NSLog(@"The size of long long is: %d.", sizeof(long long)); 17 | NSLog(@"The size of a unsigned char is: %d.", sizeof(unsigned char)); 18 | NSLog(@"The size of unsigned short is: %d.", sizeof(unsigned short)); 19 | NSLog(@"The size of unsigned int is: %d.", sizeof(unsigned int)); 20 | NSLog(@"The size of unsigned long is: %d.", sizeof(unsigned long)); 21 | NSLog(@"The size of unsigned long long is: %d.", sizeof(unsigned long long)); 22 | NSLog(@"The size of a float is: %d.", sizeof(float)); 23 | NSLog(@"The size of a double is %d.", sizeof(double)); 24 | 25 | NSLog(@"Ranges:"); 26 | NSLog(@"CHAR_MIN: %c", CHAR_MIN); 27 | NSLog(@"CHAR_MAX: %c", CHAR_MAX); 28 | NSLog(@"SHRT_MIN: %hi", SHRT_MIN); // signed short int 29 | NSLog(@"SHRT_MAX: %hi", SHRT_MAX); 30 | NSLog(@"INT_MIN: %i", INT_MIN); 31 | NSLog(@"INT_MAX: %i", INT_MAX); 32 | NSLog(@"LONG_MIN: %li", LONG_MIN); // signed long int 33 | NSLog(@"LONG_MAX: %li", LONG_MAX); 34 | NSLog(@"ULONG_MAX: %lu", ULONG_MAX); // unsigned long int 35 | NSLog(@"LLONG_MIN: %lli", LLONG_MIN); // signed long long int 36 | NSLog(@"LLONG_MAX: %lli", LLONG_MAX); 37 | NSLog(@"ULLONG_MAX: %llu", ULLONG_MAX); // unsigned long long int 38 | ``` 39 | 40 | #### 32位机 41 | 42 | ``` 43 | Primitive sizes: 44 | The size of a char is: 1. 45 | The size of short is: 2. 46 | The size of int is: 4. 47 | The size of long is: 4. 48 | The size of long long is: 8. 49 | The size of a unsigned char is: 1. 50 | The size of unsigned short is: 2. 51 | The size of unsigned int is: 4. 52 | The size of unsigned long is: 4. 53 | The size of unsigned long long is: 8. 54 | The size of a float is: 4. 55 | The size of a double is 8. 56 | Ranges: 57 | CHAR_MIN: -128 58 | CHAR_MAX: 127 59 | SHRT_MIN: -32768 60 | SHRT_MAX: 32767 61 | INT_MIN: -2147483648 62 | INT_MAX: 2147483647 63 | LONG_MIN: -2147483648 64 | LONG_MAX: 2147483647 65 | ULONG_MAX: 4294967295 66 | LLONG_MIN: -9223372036854775808 67 | LLONG_MAX: 9223372036854775807 68 | ULLONG_MAX: 18446744073709551615 69 | ``` 70 | 71 | #### 64位机 72 | 73 | ``` 74 | The size of a char is: 1. 75 | The size of short is: 2. 76 | The size of int is: 4. 77 | The size of long is: 8. 78 | The size of long long is: 8. 79 | The size of a unsigned char is: 1. 80 | The size of unsigned short is: 2. 81 | The size of unsigned int is: 4. 82 | The size of unsigned long is: 8. 83 | The size of unsigned long long is: 8. 84 | The size of a float is: 4. 85 | The size of a double is 8. 86 | Ranges: 87 | CHAR_MIN: -128 88 | CHAR_MAX: 127 89 | SHRT_MIN: -32768 90 | SHRT_MAX: 32767 91 | INT_MIN: -2147483648 92 | INT_MAX: 2147483647 93 | LONG_MIN: -9223372036854775808 94 | LONG_MAX: 9223372036854775807 95 | ULONG_MAX: 18446744073709551615 96 | LLONG_MIN: -9223372036854775808 97 | LLONG_MAX: 9223372036854775807 98 | ULLONG_MAX: 18446744073709551615 99 | ``` -------------------------------------------------------------------------------- /content/uialertcontroller-custom-font-size-color.md: -------------------------------------------------------------------------------- 1 | # UIAlertController自定义字体 2 | [UIAlertController custom font, size, color](https://stackoverflow.com/questions/26460706/uialertcontroller-custom-font-size-color) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 不确定是否与私有API属性有冲突,iOS 8 用KVC可以实现 11 | 12 | ```objc 13 | UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"Dont care what goes here, since we're about to change below" message:@"" preferredStyle:UIAlertControllerStyleActionSheet]; 14 | NSMutableAttributedString *hogan = [[NSMutableAttributedString alloc] initWithString:@"Presenting the great... Hulk Hogan!"]; 15 | [hogan addAttribute:NSFontAttributeName 16 | value:[UIFont systemFontOfSize:50.0] 17 | range:NSMakeRange(24, 11)]; 18 | [alertVC setValue:hogan forKey:@"attributedTitle"]; 19 | 20 | 21 | 22 | UIAlertAction *button = [UIAlertAction actionWithTitle:@"Label text" 23 | style:UIAlertActionStyleDefault 24 | handler:^(UIAlertAction *action){ 25 | //add code to make something happen once tapped 26 | }]; 27 | UIImage *accessoryImage = [UIImage imageNamed:@"someImage"]; 28 | [button setValue:accessoryImage forKey:@"image"]; 29 | ``` 30 | 31 | Swift: 32 | 33 | ```swift 34 | let alert = UIAlertController(title: nil, message: nil, preferredStyle: .ActionSheet) 35 | 36 | let action = UIAlertAction(title: "Some title", style: .Default, handler: nil) 37 | let attributedText = NSMutableAttributedString(string: "Some title") 38 | 39 | let range = NSRange(location: 0, length: attributedText.length) 40 | attributedText.addAttribute(NSKernAttributeName, value: 1.5, range: range) 41 | attributedText.addAttribute(NSFontAttributeName, value: UIFont(name: "ProximaNova-Semibold", size: 20.0)!, range: range) 42 | 43 | alert.addAction(action) 44 | 45 | presentViewController(alert, animated: true, completion: nil) 46 | 47 | // this has to be set after presenting the alert, otherwise the internal property __representer is nil 48 | guard let label = action.valueForKey("__representer")?.valueForKey("label") as? UILabel else { return } 49 | label.attributedText = attributedText 50 | ``` -------------------------------------------------------------------------------- /content/uibutton-how-to-center-an-image-and-a-text-using-imageedgeinsets-and-titleedgei.md: -------------------------------------------------------------------------------- 1 | # 如何使UIButton的图片和文字都居中? 2 | [UIButton: how to center an image and a text using imageEdgeInsets and titleEdgeInsets?](https://stackoverflow.com/questions/2451223/uibutton-how-to-center-an-image-and-a-text-using-imageedgeinsets-and-titleedgei) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | #### iOS6及以下用以下代码 11 | 12 | ```Objc 13 | // 图片与文字之间的距离 14 | CGFloat spacing = 6.0; 15 | 16 | // 把文字放低和居左可以文字在图片下面 17 | CGSize imageSize = button.imageView.frame.size; 18 | button.titleEdgeInsets = UIEdgeInsetsMake( 19 | 0.0, - imageSize.width, - (imageSize.height + spacing), 0.0); 20 | 21 | // 把图片放上和居右可以让图片在文字上面 22 | CGSize titleSize = button.titleLabel.frame.size; 23 | button.imageEdgeInsets = UIEdgeInsetsMake( 24 | - (titleSize.height + spacing), 0.0, 0.0, - titleSize.width); 25 | ``` 26 | 27 | #### iOS 7+ 28 | 29 | ```objc 30 | // the space between the image and text 31 | CGFloat spacing = 6.0; 32 | 33 | // lower the text and push it left so it appears centered 34 | // below the image 35 | CGSize imageSize = button.imageView.image.size; 36 | button.titleEdgeInsets = UIEdgeInsetsMake( 37 | 0.0, - imageSize.width, - (imageSize.height + spacing), 0.0); 38 | 39 | // raise the image and push it right so it appears centered 40 | // above the text 41 | CGSize titleSize = [button.titleLabel.text sizeWithAttributes:@{NSFontAttributeName: button.titleLabel.font}]; 42 | button.imageEdgeInsets = UIEdgeInsetsMake( 43 | - (titleSize.height + spacing), 0.0, 0.0, - titleSize.width); 44 | 45 | // increase the content height to avoid clipping 46 | CGFloat edgeOffset = fabsf(titleSize.height - imageSize.height) / 2.0; 47 | button.contentEdgeInsets = UIEdgeInsetsMake(edgeOffset, 0.0, edgeOffset, 0.0); 48 | ``` 49 | 50 | #### Swift 51 | 52 | ```swift 53 | extension UIButton { 54 | func alignVertical(spacing: CGFloat = 6.0) { 55 | guard let imageSize = self.imageView?.image?.size, 56 | let text = self.titleLabel?.text, 57 | let font = self.titleLabel?.font 58 | else { return } 59 | self.titleEdgeInsets = UIEdgeInsets(top: 0.0, left: -imageSize.width, bottom: -(imageSize.height + spacing), right: 0.0) 60 | let labelString = NSString(string: text) 61 | let titleSize = labelString.size(attributes: [NSFontAttributeName: font]) 62 | self.imageEdgeInsets = UIEdgeInsets(top: -(titleSize.height + spacing), left: 0.0, bottom: 0.0, right: -titleSize.width) 63 | let edgeOffset = abs(titleSize.height - imageSize.height) / 2.0; 64 | self.contentEdgeInsets = UIEdgeInsets(top: edgeOffset, left: 0.0, bottom: edgeOffset, right: 0.0) 65 | } 66 | } 67 | ``` -------------------------------------------------------------------------------- /content/uiview-frame-bounds-and-center.md: -------------------------------------------------------------------------------- 1 | # UIView的frame, bounds, center? 2 | [UIView frame, bounds and center](https://stackoverflow.com/questions/5361369/uiview-frame-bounds-and-center) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | **Frame** : `frame` (`CGRect`)是一个相对于 `superview`坐标系统的一个长方形. 默认开始是从左上. 11 | 12 | **Bounds**: `bounds` (`CGRect`) 表示的是一个以自己坐标系统为基准的长方形 13 | 14 | **Center** : `center` `CGPoint` 是在 `superview`的坐标系统上,View的中心位置 15 | 16 | 他们之间的关系如下: 17 | 18 | - `frame.origin = center - (bounds.size / 2.0)` 19 | - `center = frame.origin + (bounds.size / 2.0)` 20 | - `frame.size = bounds.size` 21 | 22 | ![img](/images/04.jpg) 23 | 24 | > 2 25 | 26 | 1、UIView中,frame其实是不存储的,而是动态计算的,改变center,改变bounds大小,或者改变transfrom都可能会导致frame的改变。 27 | 28 | ![img](/images/16.jpg) 29 | 30 | 2、Bounds的orgin并不总是(0,0),比如UIScrollView向上滑动,就有可能是(0,-10) 31 | 32 | 3、 transform不会影响到view的bounds和center,但是会影响到frame。 比如大小缩小到0.9倍,则center不变,frame.size 变为 0.9倍,origin也会跟着变。 33 | 34 | frame.size = bounds.size 35 | frame.origin.x = center.x - bounds.size.width / 2 36 | frame.origin.y = center.y - bounds.size.height / 2 -------------------------------------------------------------------------------- /content/using-a-constant-nsstring-as-the-key-for-nsuserdefaults.md: -------------------------------------------------------------------------------- 1 | # 字符串常量作为key 2 | [Using a constant NSString as the key for NSUserDefaults](https://stackoverflow.com/questions/753755/using-a-constant-nsstring-as-the-key-for-nsuserdefaults) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 应该使用 11 | 12 | ``` 13 | NSString * const kPolygonNumberOfSides = @"..."; // 一个常量指针指向一个NSString 14 | ``` 15 | 16 | 而不是 17 | 18 | ``` 19 | NSString const * kPolygonNumberOfSides = @"..."; // 一个指针指向常量相当于,const NSString * 20 | ``` 21 | 22 | 第一个是一个常量指针指向一个字符串对象,不变的是指针。 23 | 24 | 第二个是一个指针指向常量字符串,不变的是这个字符串。 25 | 26 | 有一点细微的区别,当使用 27 | 28 | ``` 29 | - (void)setObject:(id)value forKey:(NSString *)defaultName; 30 | ``` 31 | 32 | defaultName参数需要的是一个NSString *类型,当你传递的是一个指针(变量),会报Waring 33 | 34 | 另外,我需要指出用这些常量最好加上关键字static如果他们只是在一个文件内使用。因为如果你不声明为一个static,它们会作为一个全局命名变量,你在其他文件内不能使用相同名字的变量。所以最好是这样声明: 35 | 36 | ``` 37 | static NSString * const kSomeLabel = @"..."; 38 | ``` -------------------------------------------------------------------------------- /content/using-objc-setassociatedobject-with-weak-references.md: -------------------------------------------------------------------------------- 1 | # 如何objc_setAssociatedObject关联weak属性 2 | [Using objc_setAssociatedObject with weak references](https://stackoverflow.com/questions/16569840/using-objc-setassociatedobject-with-weak-references) 3 | 4 | 有OBJC_ASSOCIATION_ASSIGN这个选项,但是会不会在引用会回收后将指针置为nil? 5 | 6 | ___ 7 | 8 | 9 | 10 | > 1 11 | 12 | `OBJC_ASSOCIATION_ASSIGN` 不会在属性清空后将引用指针清空,这会造成野指针,所以是由风险去访问一个已经被清除的对象的。但是我们可以用另外的一种方法来关联一个weak属性,那就是强关联一个对象,然后让这个对象来弱引用这个属性。 13 | 14 | ```objc 15 | @interface WeakObjectContainer : NSObject 16 | @property (nonatomic, readonly, weak) id object; 17 | @end 18 | 19 | @implementation WeakObjectContainer 20 | - (instancetype) initWithObject:(id)object 21 | { 22 | if (!(self = [super init])) 23 | return nil; 24 | 25 | _object = object; 26 | 27 | return self; 28 | } 29 | @end 30 | ``` 31 | 32 | 把WeakObjectContainer对象用OBJC_ASSOCIATION_RETAIN_NONATOMIC强关联 33 | 34 | ```objc 35 | objc_setAssociatedObject(self, &MyKey, [[WeakObjectContainer alloc] initWithObject:object], OBJC_ASSOCIATION_RETAIN_NONATOMIC); 36 | ``` 37 | 38 | ```objc 39 | id object = [objc_getAssociatedObject(self, &MyKey) object]; 40 | ``` -------------------------------------------------------------------------------- /content/using-performselector-vs-just-calling-the-method.md: -------------------------------------------------------------------------------- 1 | # performSelector: vs. method 2 | [Using -performSelector: vs. just calling the method](https://stackoverflow.com/questions/1493125/using-performselector-vs-just-calling-the-method) 3 | 4 | ``` 5 | [object performSelector:@selector(doSomething)]; 6 | [object doSomething]; 7 | ``` 8 | 9 | 有什么区别? 10 | 11 | ___ 12 | 13 | 14 | 15 | > 1 16 | 17 | 一般来说,performSelector允许你动态检测哪个selector给对象进行调用,换句话说,在运行时之前,selector不会被检测。而不像Method在编译的时候就会被检测是否合适 18 | 19 | 下面这种情况两者是相同的: 20 | 21 | ``` 22 | [anObject aMethod]; 23 | [anObject performSelector:@selector(aMethod)]; 24 | ``` 25 | 26 | performSelector允许你这样做: 27 | 28 | ```objc 29 | SEL aSelector = findTheAppropriateSelectorForTheCurrentSituation(); //找到合适的selector 30 | [anObject performSelector: aSelector]; 31 | ``` 32 | 33 | 另外可以用performSelector调用不能显式调用的方法 34 | 35 | ```objc 36 | SEL aSelector = NSSelecotrFromString(@"dealloc"); //dealloc不能被显式调用 37 | [anObject performSelector: aSelector]; 38 | ``` 39 | 40 | -------------------------------------------------------------------------------- /content/vertically-align-text-to-top-within-a-uilabel.md: -------------------------------------------------------------------------------- 1 | # UILabel文字垂直居上? 2 | https://stackoverflow.com/questions/1054558/vertically-align-text-to-top-within-a-uilabel 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | UIKit自带的功能是没有办法让垂直居上的,但是可以通过`[myLabel sizeToFit];`来达到类似效果 11 | 12 | ![img](/images/01.png) 13 | 14 | 如果数量超过一行 15 | 16 | ```objc 17 | myLabel.numberOfLines = 0; 18 | [myLabel sizeToFit]; 19 | ``` 20 | 21 | ![img](/images/02.png) 22 | 23 | ___ 24 | 25 | 26 | 27 | > 2 28 | 29 | 把UILabel换成UITextView可以达到这个效果。如果你换成UITextView,你可以通过禁用交互关闭ScrollView属性,这样效果看起来更新UILabel 30 | 31 | ___ 32 | 33 | > 3 34 | 35 | 写UIlabel的子类 36 | 37 | ``` 38 | @interface MFTopAlignedLabel : UILabel 39 | 40 | @end 41 | 42 | 43 | @implementation MFTopAlignedLabel 44 | 45 | - (void)drawTextInRect:(CGRect) rect 46 | { 47 | NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:self.text attributes:@{NSFontAttributeName:self.font}]; 48 | rect.size.height = [attributedText boundingRectWithSize:rect.size 49 | options:NSStringDrawingUsesLineFragmentOrigin 50 | context:nil].size.height; 51 | if (self.numberOfLines != 0) { 52 | rect.size.height = MIN(rect.size.height, self.numberOfLines * self.font.lineHeight); 53 | } 54 | [super drawTextInRect:rect]; 55 | } 56 | 57 | @end 58 | ``` -------------------------------------------------------------------------------- /content/what-are-the-dangers-of-method-swizzling-in-objective-c.md: -------------------------------------------------------------------------------- 1 | # 使用Method-swizzling的危险? 2 | https://stackoverflow.com/questions/5339276/what-are-the-dangers-of-method-swizzling-in-objective-c 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 使用Method-swizzling会有以下陷阱: 11 | 12 | - Method-swizzling非原子性 13 | - 是一个更改非所有权的代码的行为 14 | - 可能引发命名冲突 15 | - Swizzling 改变了方法的实际参数 16 | - Swizzles的顺序导致的麻烦 17 | - 理解困难(看起来像递归) 18 | - debug困难 19 | 20 | #### Method-swizzling非原子性 21 | 22 | 我还没有看到一个Method-swizzling的方法实现在并发时是安全的,一般来说,你只是简单地想要替换一个方法,而你希望替换后的方法可以再项目的整个生命周期中使用,这意味着,你应该在`+(void)load`方法中做Method-swizzling,`load`这个类方法在APP开始阶段执行,如果你在这里进行方法替换,你可以不用担心并发。 23 | 24 | 如果你在`+(void)initialize`方法中进行方法替换,你可能让你的方法替换处于一个竞争环境,运行时会以一个诡异的状态结束。 25 | 26 | #### 更改非所有权的代码的行为 27 | 28 | 大家之所以会把这个任务是一个大问题,是因为你不仅仅改变了一个NSButton的实例,而是替换了程序中所有的NSButton的实例,出于这个原因,当你swizzle你应该小心,但你不需要完全避免它。 29 | 30 | #### 可能引发命名冲突 31 | 32 | 命名冲突出现在整个Cocoa中,我们频繁地使用前缀在方法名称中。在方法替换中,我们只需要更改一下我们之前的方式。大部分的Swilling如下: 33 | 34 | ``` 35 | @interface NSView : NSObject 36 | - (void)setFrame:(NSRect)frame; 37 | @end 38 | 39 | @implementation NSView (MyViewAdditions) 40 | 41 | - (void)my_setFrame:(NSRect)frame { 42 | // do custom work 43 | [self my_setFrame:frame]; 44 | } 45 | 46 | + (void)load { 47 | [self swizzle:@selector(setFrame:) with:@selector(my_setFrame:)]; 48 | } 49 | 50 | @end 51 | ``` 52 | 53 | 如果`my_setFrame`方法在其他地方声明了,就会有问题了,我们可以解决它: 54 | 55 | ``` 56 | @implementation NSView (MyViewAdditions) 57 | 58 | static void MySetFrame(id self, SEL _cmd, NSRect frame); 59 | static void (*SetFrameIMP)(id self, SEL _cmd, NSRect frame); 60 | 61 | static void MySetFrame(id self, SEL _cmd, NSRect frame) { 62 | // do custom work 63 | SetFrameIMP(self, _cmd, frame); 64 | } 65 | 66 | + (void)load { 67 | [self swizzle:@selector(setFrame:) with:(IMP)MySetFrame store:(IMP *)&SetFrameIMP]; 68 | } 69 | 70 | @end 71 | ``` 72 | 73 | 上面的示例可以避免命名冲突,同样可以做到方法替换。 74 | 75 | 方法替换是这样定义的: 76 | 77 | ``` 78 | typedef IMP *IMPPointer; 79 | 80 | BOOL class_swizzleMethodAndStore(Class class, SEL original, IMP replacement, IMPPointer store) { 81 | IMP imp = NULL; 82 | Method method = class_getInstanceMethod(class, original); 83 | if (method) { 84 | const char *type = method_getTypeEncoding(method); 85 | imp = class_replaceMethod(class, original, replacement, type); 86 | if (!imp) { 87 | imp = method_getImplementation(method); 88 | } 89 | } 90 | if (imp && store) { *store = imp; } 91 | return (imp != NULL); 92 | } 93 | 94 | @implementation NSObject (FRRuntimeAdditions) 95 | + (BOOL)swizzle:(SEL)original with:(IMP)replacement store:(IMPPointer)store { 96 | return class_swizzleMethodAndStore(self, original, replacement, store); 97 | } 98 | @end 99 | ``` 100 | 101 | #### 更改方法名导致的更改方法的实际参数 102 | 103 | 在我看来,这是一个大问题。你正在更改传递给原来方法声明的参数。整个过程是这样的: 104 | 105 | ``` 106 | [self my_setFrame:frame]; 107 | ``` 108 | 109 | ``` 110 | objc_msgSend(self, @selector(my_setFrame:), frame); 111 | ``` 112 | 113 | 运行时会在方法IMP列表里查找``my_setFrame:`,一但IMP找到了,它会用给的相同参数来调用IMP。运行时找到的IMP是原来的IMP`setFrame:`,所以它会在前面给调用,但是_cmd的实际参数并不是`setFrame:`而是`my_setFrame:`,原来的IMP被调用了它没有预料到它会接受的参数,这样并不好。 114 | 115 | 有一个简单的解决方案:用刚才上面的定义,可以保证实际参数永远不会被改变 116 | 117 | #### Swizzles的顺序导致的麻烦 118 | 119 | 想象一下下面这种情况: 120 | 121 | ``` 122 | [NSButton swizzle:@selector(setFrame:) with:@selector(my_buttonSetFrame:)]; 123 | [NSControl swizzle:@selector(setFrame:) with:@selector(my_controlSetFrame:)]; 124 | [NSView swizzle:@selector(setFrame:) with:@selector(my_viewSetFrame:)]; 125 | ``` 126 | 127 | NSButton也swizzle了会发生什么? 128 | 129 | 当你在一个button上面调用了`setFrame:`,将会调用已经替换后的方法,然后,直接跳到NSView里原来声明的`setFrame:`,NSControl和NSView被替换的方法不会被调用。 130 | 131 | 但是如果顺序是这样: 132 | 133 | ``` 134 | [NSView swizzle:@selector(setFrame:) with:@selector(my_viewSetFrame:)]; 135 | [NSControl swizzle:@selector(setFrame:) with:@selector(my_controlSetFrame:)]; 136 | [NSButton swizzle:@selector(setFrame:) with:@selector(my_buttonSetFrame:)]; 137 | ``` 138 | 139 | 因为NSView的方法替换是最先做的,NSControl的将会拿到正确的方法,同样的,NSButton也会从NSControl那里拿到方法`setFrame:`.这样有点困惑,但是这是正确的顺序,如何来保证这些呢? 140 | 141 | 同样的,还是要用load方法,如果你只在+load方法里进行替换,你就会安全的,load方法保证了父类加载方法在子类加载之前,这样就会拿到正确的顺序。 142 | 143 | #### 理解困难(看起来像递归) 144 | 145 | 用传统的方式来swizzled方法,会让人困惑,但是如果用我们上面的流程来替换方法,就比较容易理解了 146 | 147 | #### debug困难 148 | 149 | debug困难是因为很难记得实际声明是什么,所以做好文档。 150 | 151 | #### 总结 152 | 153 | 如果使用得当,Method-swizzling是安全的,一个安全稳定的操作就是在load方法里进行替换操作。就如同编程中的许多事情,也许会有危险,但是理解清楚就能使用得当。 154 | 155 | -------------------------------------------------------------------------------- /content/what-does-private-mean-in-objective-c.md: -------------------------------------------------------------------------------- 1 | # @private在Objective-C里是什么意思? 2 | [What does “@private” mean in Objective-C?](https://stackoverflow.com/questions/844658/what-does-private-mean-in-objective-c) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 这是一个可用标志符,它表示由`@private`声明的实例变量只能由同类的实例对象来访问, 11 | 12 | 私有成员不能被子类或者其他类访问 13 | 14 | ``` 15 | @interface MyClass : NSObject 16 | { 17 | @private 18 | int someVar; // 只能被MyClass访问 19 | 20 | @public 21 | int aPublicVar; // 可以被任意对象访问 22 | } 23 | @end 24 | ``` 25 | 26 | Objective-C中有一个隐藏的公开声明 -------------------------------------------------------------------------------- /content/what-is-nszombie.md: -------------------------------------------------------------------------------- 1 | # 什么是僵尸对象 2 | [What is NSZombie?](https://stackoverflow.com/questions/4168327/what-is-nszombie) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 这是一个内存检测助手. 特别地当你设置 `NSZombieEnabled` ,如果有一个对象的引用计数为 0, 相比于被回收,它会把自己变成 `NSZombie`实例对象,也就是僵尸对象. 当这个对象收到了方法消息, 它会在奔溃的位置显示出来,并且打印出日志为什么有问题。这样就可以检查到野指针。 11 | 12 | 野指针:指向已经被释放的对象。 13 | 14 | 错误:EXC_BAD_ACCESS/EXC_BAD_INSTRUCTION 15 | 16 | > 2 17 | 18 | 这样一段代码 19 | 20 | ```objc 21 | static NSMutableArray*array; 22 | @implementation ViewController 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | array= [[NSMutableArray alloc]initWithCapacity:5]; 26 | [array release];//释放掉该数组 27 | } 28 | 29 | - (void)viewDidAppear:(BOOL)animated{ 30 | [array addObject:@"Hello"];//使用释放掉的数组 31 | } 32 | ``` 33 | 34 | 开启僵尸对象之前: 35 | 36 | ![img](/images/10.png) 37 | 38 | 开启僵尸对象: 39 | 40 | ![img](/images/11.png) 41 | 42 | 开启僵尸对象之后: 43 | 44 | ![img](/images/12.png) 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /content/what-is-the-best-way-to-create-constants-in-objective-c.md: -------------------------------------------------------------------------------- 1 | # Objective-C声明常量的最好方式 2 | [What is the best way to create constants in Objective-C](https://stackoverflow.com/questions/17228334/what-is-the-best-way-to-create-constants-in-objective-c) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 如果常量是具体的而且在一个类的内部使用,这种常量的声明应该用`static const` ,放在.m文件的顶部位置 11 | 12 | ```objc 13 | static NSString *const MyThingNotificationKey = @"MyThingNotificationKey"; 14 | ``` 15 | 16 | 如果常量属于一个类,但是要被其他类引用,声明的时候用 `extern` 在头文件里,然后在 .m文件里定义: 17 | 18 | ```objc 19 | //.h 20 | extern NSString *const MyThingNotificationKey; 21 | 22 | //.m 23 | NSString *const MyThingNotificationKey = @"MyThingNotificationKey"; 24 | ``` 25 | 26 | 如果它们应该是全局的,则在头文件中声明它们,并在相应的模块中定义它们,特别是那些常量。 27 | 28 | 你可以根据常量的使用级别来分类这些常量 - 你可以把它们放在单独的模块中,每个模块都有自己的头文件,如果你觉得有必要的话。 29 | 30 | #### 为什么不用 `#define`? 31 | 32 | debugger并不清楚你的宏,在一个debugger命令里,你不能用 `[myThing addObserver:self forKey:MyThingNotificationKey]` 如果 `MyThingNotificationKey` 是一个宏; debugger 只能知道是否是个变量。 33 | 34 | #### 为什么不用 `enum`? 35 | 36 | `enum` 只能定义数字常量. 37 | 38 | 如果想要定义诸如序列标识符号码,位掩码,四字节代码等你应该用`enum` (最好用 [the `NS_ENUM` and `NS_OPTIONS` macros](http://nshipster.com/ns_enum-ns_options/).) -------------------------------------------------------------------------------- /content/what-is-the-difference-between-ivars-and-properties-in-objective-c.md: -------------------------------------------------------------------------------- 1 | # 实例变量(iVar)与属性(property)的区别 2 | [What is the difference between ivars and properties in Objective-C](https://stackoverflow.com/questions/4172810/what-is-the-difference-between-ivars-and-properties-in-objective-c) 3 | 4 | [Property vs. ivar in times of ARC](https://stackoverflow.com/questions/7836182/property-vs-ivar-in-times-of-arc) 5 | 6 | ```objc 7 | // MyObject.h 8 | @interface MyObject 9 | 10 | @proptery(nonatomic, copy)NSString *foo; 11 | ``` 12 | 13 | ```objc 14 | // MyObject.h 15 | @interface MyObject { 16 | NSString *foo; 17 | } 18 | ``` 19 | 20 | ___ 21 | 22 | 23 | 24 | > 1 25 | 26 | 许久以前,如果你有一个实例变量iVar, 如果你想让其他的类来访问这个变量(获取或者设置),你就必须自己分别在.h和.m文件里去定义一个getter方法和setter方法,比如 getter (i.e., `-(NSString *)foo)` , setter (i.e., `-(void)setFoo:(NSString *)aFoo;`) 27 | 28 | 属性做的就是让你从实例变量的setter和getter方法里解放出来,当你定义了一个属性,编译器会自动帮你生成setter和getter方法,你也可以自定义setter和getter方法。 29 | 30 | 为什么属性会foo会变成实例变量_foo,这是`@synthesize`做的,许多人会 @synthesize foo=_foo; 这意味着给属性foo生成一个实例变量 `_foo` ,这样的话,你就可以直接使用_foo来访问变量,而不需要通过self.foo(也就是setter和getter方法)。 31 | 32 | 在Xcode 4.6之后,你不需要使用 `@synthesize` 编译器会自动做这步操作,并且在变量前面添加 `_`. 33 | 34 | > 2 35 | 36 | - 除非自己去.h和.m文件里生成setter和getter方法,其他类不能访问实例变量 37 | - 除非自己去setter方法里实现KVO监听,实例变量没有KVO功能 38 | - 实例变量不能对对象进行属性修饰,比如NString,ARC会默认用strong修饰。如果用属性则可以用copy修饰。 -------------------------------------------------------------------------------- /content/what-is-the-difference-between-releasing-and-autoreleasing.md: -------------------------------------------------------------------------------- 1 | # autorelease和release有什么区别? 2 | [What is the difference between releasing and autoreleasing?](https://stackoverflow.com/questions/2076402/what-is-the-difference-between-releasing-and-autoreleasing) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | release意味着会被马上释放,autorelease则是将对象放入autorelasepool中,只有当autorelasepool被drain时才会被release,延迟释放。 11 | 12 | 为什么需要autorelease? 13 | 14 | 先看relase 15 | 16 | ```Objc 17 | -(void)someMethod{ 18 | MyObject *obj = [MyObject new]; 19 | 20 | //用obj做一些事情 21 | ... 22 | 23 | [obj release] 24 | } 25 | ``` 26 | 27 | 这种情况下,先持有然后再释放,obj的内存在方法结束后就被回收。就能保证内存不泄露。 28 | 29 | 但是如果这个对象在方法结束后还要继续用,就不能当即释放了,但是不release,又会造成内存泄漏。 30 | 31 | ```Objc 32 | - (MyObject *)myMethod { 33 | MyObject *obj = [MyObject new]; 34 | 35 | //用obj做一些事情 36 | ... 37 | 38 | [obj autorelease]; 39 | return obj; 40 | } 41 | ``` 42 | 43 | 这种情况下,obj暂时不会被释放 44 | 45 | ``` 46 | - (void)someOtherMethod { 47 | ... 48 | MyObject *aobj = [Instance myMethod]; 49 | 50 | } 51 | ``` 52 | 53 | aobj指向的内存,与obj一样的内存,在autoreleasepool被drain时才会回回收释放。保证内存不泄漏的同时还能保持使用。 54 | 55 | -------------------------------------------------------------------------------- /content/what-is-the-meaning-of-id.md: -------------------------------------------------------------------------------- 1 | # id类型是什么意思? 2 | [What is the meaning of id?](https://stackoverflow.com/questions/7987060/what-is-the-meaning-of-id) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | id是一个指针指向任何类型,但是与void *不同的是,id指向的是Objective-C对象,比如,你可以添加id类型的任何东西到NSArray,但是这些对象必需能够rerain和release. 11 | 12 | 编译器能够将任何对象隐式转换为id,并且可以将id转换为任何对象。 这与Objective-C中的任何其他隐式转换不同,并且是cocoa中大多数容器类型的基础。 -------------------------------------------------------------------------------- /content/whats-the-best-way-to-put-a-c-struct-in-an-nsarray.md: -------------------------------------------------------------------------------- 1 | # 数组存储结构体 2 | [What's the best way to put a c-struct in an NSArray?](https://stackoverflow.com/questions/4516991/whats-the-best-way-to-put-a-c-struct-in-an-nsarray) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 通过[NSValue](https://developer.apple.com/documentation/foundation/nsvalue)的变体Categroy来实现 11 | 12 | > An `NSValue` object can hold any of the scalar types such as `int`, `float`, and `char`, as well as pointers, structures, and object `id` references. Use this class to work with such data types in collections (such as [`NSArray`](https://developer.apple.com/documentation/foundation/nsarray) and [`NSSet`](https://developer.apple.com/documentation/foundation/nsset)), [Key-value coding](https://developer.apple.com/library/content/documentation/General/Conceptual/DevPedia-CocoaCore/KeyValueCoding.html#//apple_ref/doc/uid/TP40008195-CH25), and other APIs that require Objective-C objects. `NSValue` objects are always immutable. 13 | 14 | 一个NSValue可以存储任何的数值类型比如Int,float,char,同样也适用于指针,结构体,id对象.这个类可以用于结合类、KVC或者其他API需要OC对象的时候。 15 | 16 | ```objc 17 | typedef struct { 18 | int numFaces; 19 | float radius; 20 | } Polyhedron; 21 | 22 | @interface NSValue (Polyhedron) 23 | + (instancetype)valuewithPolyhedron:(Polyhedron)value; 24 | @property (readonly) Polyhedron polyhedronValue; 25 | @end 26 | 27 | @implementation NSValue (Polyhedron) 28 | + (instancetype)valuewithPolyhedron:(Polyhedron)value 29 | { 30 | return [self valueWithBytes:&value objCType:@encode(Polyhedron)]; 31 | } 32 | - (Polyhedron) polyhedronValue 33 | { 34 | Polyhedron value; 35 | [self getValue:&value]; 36 | return value; 37 | } 38 | @end 39 | ``` 40 | 41 | 数组里存储NSValue就行了 -------------------------------------------------------------------------------- /content/whats-the-difference-between-a-method-and-a-selector.md: -------------------------------------------------------------------------------- 1 | # Method vs. selector vs. IMP 2 | [What's the difference between a method and a selector?](https://stackoverflow.com/questions/5608476/whats-the-difference-between-a-method-and-a-selector) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | - **Selector** - 一个Selector是一个方法的名字. 你应该对这些selectors很熟悉: `alloc`, `init`, `release`, `dictionaryWithObjectsAndKeys:`, `setObject:forKey:`, 注意,冒号是selector的一部分,用来定义我们需要的参数. 甚至于(尽管很少, Cocoa frameworks看不到), 你可以有一个selectors 像这样 `doFoo:::`. 这是一个方法需要三个参数,你可以这样调用 `[someObject doFoo:arg1 :arg2 :arg3]`,也就是没有必要再每个参数前面都要有字母。 你可以直接使用selectors在Cocoa. 有相应的类型 `SEL`: `SEL aSelector = @selector(doSomething:)` or `SEL aSelector = NSSelectorFromString(@"doSomething:");` 11 | - **Message** - 消息,是在Runtime时,selector和对应的参数被发送的消息. 消息可以封装在一个 `NSInvocation` 对象里供以后调用. 消息会被发送给一个 *receiver*. (对象会接受这个消息). 12 | - **Method** - 方法是selector和一个声明的联合. "声明" 是一个函数指针 (an `IMP`). 一个实际的方法可以在内部使用一个Method结构体来检索(可以从运行时检索到)。 13 | 14 | 15 | - **Method Signature** - 方法签名表示由方法返回并接受的数据类型。 它们可以在运行时通过NSMethodSignature和(在某些情况下)一个原始char *来表示。 16 | - **Implementation** -方法的实际执行代码. 在运行时的类型是 `IMP`, 是一个函数指针. -------------------------------------------------------------------------------- /content/whats-the-difference-between-the-atomic-and-nonatomic-attributes.md: -------------------------------------------------------------------------------- 1 | # atomic和nonatomic有什么区别? 2 | [What's the difference between the atomic and nonatomic attributes?](https://stackoverflow.com/questions/588866/whats-the-difference-between-the-atomic-and-nonatomic-attributes) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 使用atomic,`synthesized setter/getter `将会确保整个属性总是会从getter中取值或者从setter去赋值,不管其他线程的赋值操作。就是说,如果线程A在取值getter的时候,线程B调用了setter赋值操作,一个实际可用的值--一个autoreleased对象—将会返回在A线程。也就是说有互斥。 11 | 12 | 使用nonatomic的时候,没有上面这种保证,所以,nonatomic被认为比atomic更快 13 | 14 | atomic并没有确保线程安全,如果线程A在调用getter取值的同时线程B和线程C在调用setter赋值不同的值,线程A有可能得到三个值中的任何一个:之前赋值或者BC线程赋的值,没有办法知道是哪个值。 15 | 16 | 确保数据完整性—多线程编程的一个主要挑战—是用过其他手段来实现的。 17 | 18 | 附加: 19 | 20 | 一个属性的atomicity同样无法确保线程安全当需要依赖多个属性时。 21 | 22 | [苹果官方文档举例](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html#//apple_ref/doc/uid/TP40011210-CH5-SW1) 23 | 24 | > **Note:** Property atomicity is not synonymous with an object’s *thread safety*.Consider an `XYZPerson` object in which both a person’s first and last names are changed using atomic accessors from one thread. If another thread accesses both names at the same time, the atomic getter methods will return complete strings (without crashing), but there’s no guarantee that those values will be the right names relative to each other. If the first name is accessed before the change, but the last name is accessed after the change, you’ll end up with an inconsistent, mismatched pair of names.This example is quite simple, but the problem of thread safety becomes much more complex when considered across a network of related objects. Thread safety is covered in more detail in *Concurrency Programming Guide*. 25 | 26 | 如果fullName=firstName+lastName;则不能保证fullName的线性安全。 27 | 28 | ___ 29 | 30 | 31 | 32 | > 2 33 | 34 | ``` 35 | //@property(nonatomic, retain) UITextField *userName; 36 | //Generates roughly 37 | 38 | - (UITextField *) userName { 39 | return userName; 40 | } 41 | 42 | - (void) setUserName:(UITextField *)userName_ { 43 | [userName_ retain]; 44 | [userName release]; 45 | userName = userName_; 46 | } 47 | ``` 48 | 49 | atomic会更复杂一些 50 | 51 | ``` 52 | //@property(retain) UITextField *userName; 53 | //Generates roughly 54 | 55 | - (UITextField *) userName { 56 | UITextField *retval = nil; 57 | @synchronized(self) { 58 | retval = [[userName retain] autorelease]; 59 | } 60 | return retval; 61 | } 62 | 63 | - (void) setUserName:(UITextField *)userName_ { 64 | @synchronized(self) { 65 | [userName_ retain]; 66 | [userName release]; 67 | userName = userName_; 68 | } 69 | } 70 | ``` 71 | 72 | 一般来说,atomic有设置互斥锁来保证线程安全,并且还要对象的引用计数+1(并且自动释放计数来平衡),这样才能保证调用者能够获得对象,否则另外一个线程在设置这个值得时候可能会使引用计数归为0。 73 | 74 | 实际上会有许多变种,取决于属性值或者对象是retain, copy, readonly, nonatomic。一般来说,针对这些可能性,synthesizers会做出正确的事。 -------------------------------------------------------------------------------- /content/when-is-it-better-to-use-an-nsset-over-an-nsarray.md: -------------------------------------------------------------------------------- 1 | # NSSet vs. NSArray 2 | [When is it better to use an NSSet over an NSArray?](https://stackoverflow.com/questions/10997404/when-is-it-better-to-use-an-nsset-over-an-nsarray) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | [苹果官方文档](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Collections/Collections.html) 11 | 12 | ![img](/images/07.png) 13 | 14 | 最大的不同就是NSArray是一个有序的集合,NSSet是一个无序的集合。查找某个对象NSSet会比较快,因为NSSet是通过hashkey来查找,而NSArray是通过遍历整体才能查找到。 15 | 16 | 如果你想遍历一个结合,不需要有序,NSSet性能更好,插入和删除都更快,但是很多情况,有些事情只有NSArray可以做。 17 | 18 | **NSSet** 19 | 20 | - 主要通过比较来获取项目 21 | - 无序 22 | - 不允许重复 23 | - 快速插入、删除和查看是否存在某个item 24 | 25 | **NSArray** 26 | 27 | - 可以根据序号来获取项目 28 | - 有序 29 | - 允许重复 -------------------------------------------------------------------------------- /content/when-to-use-enumerateobjectsusingblock-vs-for.md: -------------------------------------------------------------------------------- 1 | # for vs. enumerateObjectsUsingBlock 2 | [When to use enumerateObjectsUsingBlock vs. for](https://stackoverflow.com/questions/4486622/when-to-use-enumerateobjectsusingblock-vs-for) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 根据上下文来选择你需要的遍历模式 11 | 12 | `for(... in ...)` 使用方便,句法简洁。 13 | 14 | `enumerateObjectsUsingBlock:` 有一些你会认为有趣或者无趣的特点。 15 | 16 | - `enumerateObjectsUsingBlock:` 会比for循环更快 (`for(... in ...)` 用的是 `NSFastEnumeration` 进行快速枚举). For循环需要从内部表示转变到快速枚举的表示,这样会有瓶颈。 基于块的枚举允许集合类以尽可能快的方式枚举内容,快速遍历本地存储格式。对于数组来说可能差别不大,但是对于字典会有很大的区别。 17 | - "当你需要修改局部变量的时候不要用enumerateObjectsUsingBlock" - 这句话是不对的,因为你可以用 `__block` 来修饰变量,这样的话就可以修改变量。 18 | - `enumerateObjectsWithOptions:usingBlock:` 支持方向或者正向遍历。 19 | - 用字典的话,基于块的枚举是同时检索关键字和值得唯一方法。 20 | 21 | 22 | > 2 23 | 24 | GCD apply也支持循环遍历 25 | 26 | ```objc 27 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); 28 | dispatch_apply([array count], queue, ^(size_t idx) { 29 | id obj = [array objectAtIndex: idx]; 30 | /* Do something with |obj|. */ 31 | }); 32 | ``` 33 | 34 | -------------------------------------------------------------------------------- /content/when-to-use-nsinteger-vs-int.md: -------------------------------------------------------------------------------- 1 | # 什么情况下使用NSInteger或者Int? 2 | [When to use NSInteger vs. int](https://stackoverflow.com/questions/4445173/when-to-use-nsinteger-vs-int) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | 当你不知道你的处理器架构的时候,你应该使用 `NSInteger` ,这样的话,在有些情况下会得到比 `int` 更大的类型, 因为在32位CPU里是 `int`, 但是在64位系统里则是 `long`. 11 | 12 | 我坚持使用 `NSInteger` 而不是 `int`/`long` ,除非你真的特别需要. 13 | 14 | `NSInteger`/`NSUInteger` 的定义是动态类型 `typedef`: 15 | 16 | ``` 17 | #if __LP64__ || TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64 18 | typedef long NSInteger; 19 | typedef unsigned long NSUInteger; 20 | #else 21 | typedef int NSInteger; 22 | typedef unsigned int NSUInteger; 23 | #endif 24 | ``` -------------------------------------------------------------------------------- /content/zz.md: -------------------------------------------------------------------------------- 1 | # 什么情况下使用NSInteger或者Int? 2 | [When to use NSInteger vs. int](https://stackoverflow.com/questions/4445173/when-to-use-nsinteger-vs-int) 3 | 4 | ___ 5 | 6 | 7 | 8 | > 1 9 | 10 | -------------------------------------------------------------------------------- /images/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloted/stackoverflow_top_ios/20e7d206cd471a8b25f917683d9e3917296d2814/images/01.png -------------------------------------------------------------------------------- /images/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloted/stackoverflow_top_ios/20e7d206cd471a8b25f917683d9e3917296d2814/images/02.png -------------------------------------------------------------------------------- /images/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloted/stackoverflow_top_ios/20e7d206cd471a8b25f917683d9e3917296d2814/images/03.png -------------------------------------------------------------------------------- /images/04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloted/stackoverflow_top_ios/20e7d206cd471a8b25f917683d9e3917296d2814/images/04.jpg -------------------------------------------------------------------------------- /images/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloted/stackoverflow_top_ios/20e7d206cd471a8b25f917683d9e3917296d2814/images/05.png -------------------------------------------------------------------------------- /images/06.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloted/stackoverflow_top_ios/20e7d206cd471a8b25f917683d9e3917296d2814/images/06.jpg -------------------------------------------------------------------------------- /images/07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloted/stackoverflow_top_ios/20e7d206cd471a8b25f917683d9e3917296d2814/images/07.png -------------------------------------------------------------------------------- /images/08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloted/stackoverflow_top_ios/20e7d206cd471a8b25f917683d9e3917296d2814/images/08.png -------------------------------------------------------------------------------- /images/09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloted/stackoverflow_top_ios/20e7d206cd471a8b25f917683d9e3917296d2814/images/09.png -------------------------------------------------------------------------------- /images/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloted/stackoverflow_top_ios/20e7d206cd471a8b25f917683d9e3917296d2814/images/10.png -------------------------------------------------------------------------------- /images/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloted/stackoverflow_top_ios/20e7d206cd471a8b25f917683d9e3917296d2814/images/11.png -------------------------------------------------------------------------------- /images/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloted/stackoverflow_top_ios/20e7d206cd471a8b25f917683d9e3917296d2814/images/12.png -------------------------------------------------------------------------------- /images/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloted/stackoverflow_top_ios/20e7d206cd471a8b25f917683d9e3917296d2814/images/13.png -------------------------------------------------------------------------------- /images/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloted/stackoverflow_top_ios/20e7d206cd471a8b25f917683d9e3917296d2814/images/14.png -------------------------------------------------------------------------------- /images/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloted/stackoverflow_top_ios/20e7d206cd471a8b25f917683d9e3917296d2814/images/15.png -------------------------------------------------------------------------------- /images/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloted/stackoverflow_top_ios/20e7d206cd471a8b25f917683d9e3917296d2814/images/16.png --------------------------------------------------------------------------------