appjam 0.1.8.8 → 0.1.8.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (168) hide show
  1. data/README.md +22 -62
  2. data/lib/appjam/generators/gist.yml +1 -1
  3. data/lib/appjam/generators/templates/blank/EiffelApplication.xcodeproj/project.pbxproj +1166 -482
  4. data/lib/appjam/generators/templates/blank/EiffelApplication.xcodeproj/project.xcworkspace/xcuserdata/eiffel.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  5. data/lib/appjam/generators/templates/blank/EiffelApplication/EiffelApplication-Prefix.pch.tt +26 -0
  6. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/AwesomeMenu/AwesomeMenu.h +52 -0
  7. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/AwesomeMenu/AwesomeMenu.m +412 -0
  8. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/AwesomeMenu/AwesomeMenuItem.h +44 -0
  9. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/AwesomeMenu/AwesomeMenuItem.m +97 -0
  10. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/AwesomeMenu/Images/bg-addbutton-highlighted.png +0 -0
  11. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/AwesomeMenu/Images/bg-addbutton-highlighted@2x.png +0 -0
  12. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/AwesomeMenu/Images/bg-addbutton.png +0 -0
  13. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/AwesomeMenu/Images/bg-addbutton@2x.png +0 -0
  14. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/AwesomeMenu/Images/bg-menuitem-highlighted.png +0 -0
  15. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/AwesomeMenu/Images/bg-menuitem-highlighted@2x.png +0 -0
  16. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/AwesomeMenu/Images/bg-menuitem.png +0 -0
  17. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/AwesomeMenu/Images/bg-menuitem@2x.png +0 -0
  18. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/AwesomeMenu/Images/icon-plus-highlighted.png +0 -0
  19. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/AwesomeMenu/Images/icon-plus-highlighted@2x.png +0 -0
  20. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/AwesomeMenu/Images/icon-plus.png +0 -0
  21. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/AwesomeMenu/Images/icon-plus@2x.png +0 -0
  22. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/AwesomeMenu/Images/icon-star.png +0 -0
  23. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/AwesomeMenu/Images/icon-star@2x.png +0 -0
  24. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/CMPopTipView/CMPopTipView.h +167 -0
  25. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/CMPopTipView/CMPopTipView.m +639 -0
  26. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/FXLabel/FXLabel.h +97 -0
  27. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/FXLabel/FXLabel.m +1080 -0
  28. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/MBProgressHUD/MBProgressHUD.h +451 -0
  29. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/MBProgressHUD/MBProgressHUD.m +865 -0
  30. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/FacingView.h +42 -0
  31. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/FacingView.m +56 -0
  32. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/FoldView.h +90 -0
  33. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/FoldView.m +316 -0
  34. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/MultiFoldView.h +104 -0
  35. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/MultiFoldView.m +516 -0
  36. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/PaperFoldConstants.h +49 -0
  37. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/PaperFoldNavigationController.h +18 -0
  38. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/PaperFoldNavigationController.m +88 -0
  39. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/PaperFoldResources.bundle/swipe_guide_left.png +0 -0
  40. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/PaperFoldResources.bundle/swipe_guide_left@2x.png +0 -0
  41. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/PaperFoldResources.bundle/swipe_guide_right.png +0 -0
  42. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/PaperFoldResources.bundle/swipe_guide_right@2x.png +0 -0
  43. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/PaperFoldSwipeHintView.h +25 -0
  44. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/PaperFoldSwipeHintView.m +76 -0
  45. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/PaperFoldView.h +131 -0
  46. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/PaperFoldView.m +941 -0
  47. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/Resources/swipe_guide.psd +0 -0
  48. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/Resources/swipe_guide2.psd +0 -0
  49. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/ShadowView.h +46 -0
  50. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/ShadowView.m +82 -0
  51. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/TouchThroughUIView.h +39 -0
  52. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/TouchThroughUIView.m +72 -0
  53. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/UIView+Screenshot.h +42 -0
  54. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/PaperFold/UIView+Screenshot.m +100 -0
  55. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIBubbleTableView/NSBubbleData.h +34 -0
  56. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIBubbleTableView/NSBubbleData.m +140 -0
  57. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIBubbleTableView/UIBubbleHeaderTableViewCell.h +17 -0
  58. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIBubbleTableView/UIBubbleHeaderTableViewCell.m +57 -0
  59. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIBubbleTableView/UIBubbleTableView.h +30 -0
  60. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIBubbleTableView/UIBubbleTableView.m +233 -0
  61. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIBubbleTableView/UIBubbleTableViewCell.h +19 -0
  62. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIBubbleTableView/UIBubbleTableViewCell.m +122 -0
  63. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIBubbleTableView/UIBubbleTableViewDataSource.h +24 -0
  64. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIBubbleTableView/UIBubbleTypingTableViewCell.h +20 -0
  65. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIBubbleTableView/UIBubbleTypingTableViewCell.m +56 -0
  66. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIBubbleTableView/images/bubbleMine.png +0 -0
  67. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIBubbleTableView/images/bubbleMine@2x.png +0 -0
  68. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIBubbleTableView/images/bubbleSomeone.png +0 -0
  69. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIBubbleTableView/images/bubbleSomeone@2x.png +0 -0
  70. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIBubbleTableView/images/missingAvatar.png +0 -0
  71. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIBubbleTableView/images/missingAvatar@2x.png +0 -0
  72. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIBubbleTableView/images/typingMine.png +0 -0
  73. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIBubbleTableView/images/typingMine@2x.png +0 -0
  74. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIBubbleTableView/images/typingSomeone.png +0 -0
  75. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIBubbleTableView/images/typingSomeone@2x.png +0 -0
  76. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIGlossyButton/UIGlossyButton.h +124 -0
  77. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIGlossyButton/UIGlossyButton.m +545 -0
  78. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIGlossyButton/UIView+LayerEffects.h +22 -0
  79. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/components/UIGlossyButton/UIView+LayerEffects.m +32 -0
  80. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/AFIncrementalStore/AFIncrementalStore.h +344 -0
  81. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/AFIncrementalStore/AFIncrementalStore.m +848 -0
  82. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/AFIncrementalStore/AFRESTClient.h +135 -0
  83. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/AFIncrementalStore/AFRESTClient.m +441 -0
  84. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/InflectorKit/NSString+InflectorKit.h +40 -0
  85. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/InflectorKit/NSString+InflectorKit.m +36 -0
  86. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/InflectorKit/TTTStringInflector.h +76 -0
  87. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/InflectorKit/TTTStringInflector.m +270 -0
  88. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/SDWebImage/MKAnnotationView+WebCache.h +95 -0
  89. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/SDWebImage/MKAnnotationView+WebCache.m +78 -0
  90. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/SDWebImage/SDImageCache.h +144 -0
  91. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/SDWebImage/SDImageCache.m +311 -0
  92. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/SDWebImage/SDWebImageCompat.h +40 -0
  93. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/SDWebImage/SDWebImageCompat.m +54 -0
  94. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/SDWebImage/SDWebImageDecoder.h +18 -0
  95. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/SDWebImage/SDWebImageDecoder.m +70 -0
  96. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/SDWebImage/SDWebImageDownloader.h +102 -0
  97. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/SDWebImage/SDWebImageDownloader.m +226 -0
  98. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/SDWebImage/SDWebImageDownloaderOperation.h +25 -0
  99. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/SDWebImage/SDWebImageDownloaderOperation.m +339 -0
  100. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/SDWebImage/SDWebImageManager.h +167 -0
  101. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/SDWebImage/SDWebImageManager.m +244 -0
  102. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/SDWebImage/SDWebImageOperation.h +15 -0
  103. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/SDWebImage/SDWebImagePrefetcher.h +58 -0
  104. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/SDWebImage/SDWebImagePrefetcher.m +127 -0
  105. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/SDWebImage/UIButton+WebCache.h +173 -0
  106. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/SDWebImage/UIButton+WebCache.m +129 -0
  107. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/SDWebImage/UIImageView+WebCache.h +140 -0
  108. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/frameworks/SDWebImage/UIImageView+WebCache.m +84 -0
  109. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CPAnimationSequence/CPAnimationProgram.h +28 -0
  110. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CPAnimationSequence/CPAnimationSequence.h +28 -0
  111. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CPAnimationSequence/CPAnimationStep.h +49 -0
  112. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CPAnimationSequence/private/CPAnimationProgram.m +100 -0
  113. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CPAnimationSequence/private/CPAnimationSequence.m +85 -0
  114. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CPAnimationSequence/private/CPAnimationStep.m +122 -0
  115. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaAsyncSocket/GCDAsyncSocket.h +1074 -0
  116. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaAsyncSocket/GCDAsyncSocket.m +7430 -0
  117. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/Categories/DDData.h +14 -0
  118. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/Categories/DDData.m +158 -0
  119. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/Categories/DDNumber.h +12 -0
  120. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/Categories/DDNumber.m +88 -0
  121. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/Categories/DDRange.h +56 -0
  122. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/Categories/DDRange.m +104 -0
  123. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/HTTPAuthenticationRequest.h +45 -0
  124. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/HTTPAuthenticationRequest.m +195 -0
  125. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/HTTPConnection.h +119 -0
  126. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/HTTPConnection.m +2708 -0
  127. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/HTTPLogging.h +136 -0
  128. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/HTTPMessage.h +48 -0
  129. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/HTTPMessage.m +113 -0
  130. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/HTTPResponse.h +149 -0
  131. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/HTTPServer.h +205 -0
  132. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/HTTPServer.m +772 -0
  133. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/Mime/MultipartFormDataParser.h +65 -0
  134. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/Mime/MultipartFormDataParser.m +529 -0
  135. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/Mime/MultipartMessageHeader.h +33 -0
  136. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/Mime/MultipartMessageHeader.m +86 -0
  137. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/Mime/MultipartMessageHeaderField.h +23 -0
  138. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/Mime/MultipartMessageHeaderField.m +211 -0
  139. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/Responses/HTTPAsyncFileResponse.h +75 -0
  140. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/Responses/HTTPAsyncFileResponse.m +405 -0
  141. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/Responses/HTTPDataResponse.h +13 -0
  142. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/Responses/HTTPDataResponse.m +79 -0
  143. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/Responses/HTTPDynamicFileResponse.h +52 -0
  144. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/Responses/HTTPDynamicFileResponse.m +292 -0
  145. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/Responses/HTTPErrorResponse.h +9 -0
  146. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/Responses/HTTPErrorResponse.m +38 -0
  147. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/Responses/HTTPFileResponse.h +25 -0
  148. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/Responses/HTTPFileResponse.m +237 -0
  149. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/Responses/HTTPRedirectResponse.h +12 -0
  150. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/Responses/HTTPRedirectResponse.m +73 -0
  151. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/WebSocket.h +105 -0
  152. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Core/WebSocket.m +791 -0
  153. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Extensions/WebDAV/DAVConnection.h +7 -0
  154. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Extensions/WebDAV/DAVConnection.m +160 -0
  155. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Extensions/WebDAV/DAVResponse.h +11 -0
  156. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Extensions/WebDAV/DAVResponse.m +372 -0
  157. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Extensions/WebDAV/DELETEResponse.h +7 -0
  158. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Extensions/WebDAV/DELETEResponse.m +49 -0
  159. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Extensions/WebDAV/PUTResponse.h +8 -0
  160. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/CocoaHTTPServer/Extensions/WebDAV/PUTResponse.m +69 -0
  161. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/hpple/TFHpple.h +54 -0
  162. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/hpple/TFHpple.m +102 -0
  163. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/hpple/TFHppleElement.h +103 -0
  164. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/hpple/TFHppleElement.m +200 -0
  165. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/hpple/XPathQuery.h +10 -0
  166. data/lib/appjam/generators/templates/blank/EiffelApplication/libs/toolkit/hpple/XPathQuery.m +197 -0
  167. data/lib/appjam/version.rb +1 -1
  168. metadata +164 -3
@@ -0,0 +1,22 @@
1
+ //
2
+ // UIView+ExtraAnimation.h
3
+ //
4
+ // Created by Water Lou on 15/09/2010.
5
+ // Copyright 2010 First Water Tech Ltd. All rights reserved.
6
+ //
7
+ // many visual effects and animation effects create using CoreAnimation and CALayer
8
+ //
9
+
10
+ #import <Foundation/Foundation.h>
11
+
12
+ @interface UIView(LayerEffects)
13
+
14
+ // set round corner
15
+ - (void) setCornerRadius : (CGFloat) radius;
16
+ // set inner border
17
+ - (void) setBorder : (UIColor *) color width : (CGFloat) width;
18
+ // set the shadow
19
+ // Example: [view setShadow:[UIColor blackColor] opacity:0.5 offset:CGSizeMake(1.0, 1.0) blueRadius:3.0];
20
+ - (void) setShadow : (UIColor *)color opacity:(CGFloat)opacity offset:(CGSize) offset blurRadius:(CGFloat)blurRadius;
21
+
22
+ @end
@@ -0,0 +1,32 @@
1
+ //
2
+ // UIView+LayerEffects.m
3
+ //
4
+ // Created by Water Lou on 15/09/2010.
5
+ // Copyright 2010 First Water Tech Ltd. All rights reserved.
6
+ //
7
+
8
+ #import <QuartzCore/QuartzCore.h>
9
+ #import "UIView+LayerEffects.h"
10
+
11
+ @implementation UIView(LayerEffects)
12
+
13
+ /* simple setting using the layer */
14
+ - (void) setCornerRadius : (CGFloat) radius {
15
+ self.layer.cornerRadius = radius;
16
+ }
17
+
18
+ - (void) setBorder : (UIColor *) color width : (CGFloat) width {
19
+ self.layer.borderColor = [color CGColor];
20
+ self.layer.borderWidth = width;
21
+ }
22
+
23
+ - (void) setShadow : (UIColor *)color opacity:(CGFloat)opacity offset:(CGSize)offset blurRadius:(CGFloat)blurRadius {
24
+ CALayer *l = self.layer;
25
+ l.shadowColor = [color CGColor];
26
+ l.shadowOpacity = opacity;
27
+ l.shadowOffset = offset;
28
+ l.shadowRadius = blurRadius;
29
+ }
30
+
31
+
32
+ @end
@@ -0,0 +1,344 @@
1
+ // AFIncrementalStore.h
2
+ //
3
+ // Copyright (c) 2012 Mattt Thompson (http://mattt.me)
4
+ //
5
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ // of this software and associated documentation files (the "Software"), to deal
7
+ // in the Software without restriction, including without limitation the rights
8
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ // copies of the Software, and to permit persons to whom the Software is
10
+ // furnished to do so, subject to the following conditions:
11
+ //
12
+ // The above copyright notice and this permission notice shall be included in
13
+ // all copies or substantial portions of the Software.
14
+ //
15
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ // THE SOFTWARE.
22
+
23
+ #import <CoreData/CoreData.h>
24
+ #import "AFNetworking.h"
25
+
26
+ @protocol AFIncrementalStoreHTTPClient;
27
+
28
+ /**
29
+ `AFIncrementalStore` is an abstract subclass of `NSIncrementalStore`, designed to allow you to load and save data incrementally to and from a one or more web services.
30
+
31
+ ## Subclassing Notes
32
+
33
+ ### Methods to Override
34
+
35
+ In a subclass of `AFIncrementalStore`, you _must_ override the following methods to provide behavior appropriate for your store:
36
+
37
+ - `+type`
38
+ - `+model`
39
+
40
+ Additionally, all `NSPersistentStore` subclasses, and thus all `AFIncrementalStore` subclasses must do `NSPersistentStoreCoordinator +registerStoreClass:forStoreType:` in order to be created by `NSPersistentStoreCoordinator -addPersistentStoreWithType:configuration:URL:options:error:`. It is recommended that subclasses register themselves in their own `+initialize` method.
41
+
42
+ Optionally, `AFIncrementalStore` subclasses can override the following methods:
43
+
44
+ - `-executeFetchRequest:withContext:error:`
45
+ - `-executeSaveChangesRequest:withContext:error:`
46
+
47
+ ### Methods Not To Be Overridden
48
+
49
+ Subclasses should not override `-executeRequest:withContext:error`. Instead, override `-executeFetchRequest:withContext:error:` or `-executeSaveChangesRequest:withContext:error:`, which are called by `-executeRequest:withContext:error` depending on the type of persistent store request.
50
+ */
51
+ @interface AFIncrementalStore : NSIncrementalStore
52
+
53
+ ///---------------------------------------------
54
+ /// @name Accessing Incremental Store Properties
55
+ ///---------------------------------------------
56
+
57
+ /**
58
+ The HTTP client used to manage requests and responses with the associated web services.
59
+ */
60
+ @property (nonatomic, strong) AFHTTPClient <AFIncrementalStoreHTTPClient> *HTTPClient;
61
+
62
+ /**
63
+ The persistent store coordinator used to persist data from the associated web serivices locally.
64
+
65
+ @discussion Rather than persist values directly, `AFIncrementalStore` manages and proxies through a persistent store coordinator.
66
+ */
67
+ @property (readonly) NSPersistentStoreCoordinator *backingPersistentStoreCoordinator;
68
+
69
+ ///-----------------------
70
+ /// @name Required Methods
71
+ ///-----------------------
72
+
73
+ /**
74
+ Returns the string used as the `NSStoreTypeKey` value by the application's persistent store coordinator.
75
+
76
+ @return The string used to describe the type of the store.
77
+ */
78
+ + (NSString *)type;
79
+
80
+ /**
81
+ Returns the managed object model used by the store.
82
+
83
+ @return The managed object model used by the store
84
+ */
85
+ + (NSManagedObjectModel *)model;
86
+
87
+ ///-----------------------
88
+ /// @name Optional Methods
89
+ ///-----------------------
90
+
91
+ /**
92
+
93
+ */
94
+ - (id)executeFetchRequest:(NSFetchRequest *)fetchRequest
95
+ withContext:(NSManagedObjectContext *)context
96
+ error:(NSError *__autoreleasing *)error;
97
+
98
+ /**
99
+
100
+ */
101
+ - (id)executeSaveChangesRequest:(NSSaveChangesRequest *)saveChangesRequest
102
+ withContext:(NSManagedObjectContext *)context
103
+ error:(NSError *__autoreleasing *)error;
104
+
105
+ @end
106
+
107
+ #pragma mark -
108
+
109
+ /**
110
+ The `AFIncrementalStoreHTTPClient` protocol defines the methods used by the HTTP client to interract with the associated web services of an `AFIncrementalStore`.
111
+ */
112
+ @protocol AFIncrementalStoreHTTPClient <NSObject>
113
+
114
+ ///-----------------------
115
+ /// @name Required Methods
116
+ ///-----------------------
117
+
118
+ /**
119
+ Returns an `NSDictionary` or an `NSArray` of `NSDictionaries` containing the representations of the resources found in a response object.
120
+
121
+ @discussion For example, if `GET /users` returned an `NSDictionary` with an array of users keyed on `"users"`, this method would return the keyed array. Conversely, if `GET /users/123` returned a dictionary with all of the atributes of the requested user, this method would simply return that dictionary.
122
+
123
+ @param entity The entity represented
124
+ @param responseObject The response object returned from the server.
125
+
126
+ @return An `NSDictionary` with the representation or an `NSArray` of `NSDictionaries` containing the resource representations.
127
+ */
128
+ - (id)representationOrArrayOfRepresentationsOfEntity:(NSEntityDescription *)entity
129
+ fromResponseObject:(id)responseObject;
130
+
131
+ /**
132
+ Returns an `NSDictionary` containing the representations of associated objects found within the representation of a response object, keyed by their relationship name.
133
+
134
+ @discussion For example, if `GET /albums/123` returned the representation of an album, including the tracks as sub-entities, keyed under `"tracks"`, this method would return a dictionary with an array of representations for those objects, keyed under the name of the relationship used in the model (which is likely also to be `"tracks"`). Likewise, if an album also contained a representation of its artist, that dictionary would contain a dictionary representation of that artist, keyed under the name of the relationship used in the model (which is likely also to be `"artist"`).
135
+
136
+ @param representation The resource representation.
137
+ @param entity The entity for the representation.
138
+ @param response The HTTP response for the resource request.
139
+
140
+ @return An `NSDictionary` containing representations of relationships, keyed by relationship name.
141
+ */
142
+ - (NSDictionary *)representationsForRelationshipsFromRepresentation:(NSDictionary *)representation
143
+ ofEntity:(NSEntityDescription *)entity
144
+ fromResponse:(NSHTTPURLResponse *)response;
145
+
146
+ /**
147
+ Returns the resource identifier for the resource whose representation of an entity came from the specified HTTP response. A resource identifier is a string that uniquely identifies a particular resource among all resource types. If new attributes come back for an existing resource identifier, the managed object associated with that resource identifier will be updated, rather than a new object being created.
148
+
149
+ @discussion For example, if `GET /posts` returns a collection of posts, the resource identifier for any particular one might be its URL-safe "slug" or parameter string, or perhaps its numeric id. For example: `/posts/123` might be a resource identifier for a particular post.
150
+
151
+ @param representation The resource representation.
152
+ @param entity The entity for the representation.
153
+ @param response The HTTP response for the resource request.
154
+
155
+ @return An `NSString` resource identifier for the resource.
156
+ */
157
+ - (NSString *)resourceIdentifierForRepresentation:(NSDictionary *)representation
158
+ ofEntity:(NSEntityDescription *)entity
159
+ fromResponse:(NSHTTPURLResponse *)response;
160
+
161
+ /**
162
+ Returns the attributes for the managed object corresponding to the representation of an entity from the specified response. This method is used to get the attributes of the managed object from its representation returned in `-representationOrArrayOfRepresentationsFromResponseObject` or `representationsForRelationshipsFromRepresentation:ofEntity:fromResponse:`.
163
+
164
+ @discussion For example, if the representation returned from `GET /products/123` had a `description` field that corresponded with the `productDescription` attribute in its Core Data model, this method would set the value of the `productDescription` key in the returned dictionary to the value of the `description` field in representation.
165
+
166
+ @param representation The resource representation.
167
+ @param entity The entity for the representation.
168
+ @param response The HTTP response for the resource request.
169
+
170
+ @return An `NSDictionary` containing the attributes for a managed object.
171
+ */
172
+ - (NSDictionary *)attributesForRepresentation:(NSDictionary *)representation
173
+ ofEntity:(NSEntityDescription *)entity
174
+ fromResponse:(NSHTTPURLResponse *)response;
175
+
176
+ /**
177
+ Returns a URL request object for the specified fetch request within a particular managed object context.
178
+
179
+ @discussion For example, if the fetch request specified the `User` entity, this method might return an `NSURLRequest` with `GET /users` if the web service was RESTful, `POST /endpoint?method=users.getAll` for an RPC-style system, or a request with an XML envelope body for a SOAP webservice.
180
+
181
+ @param fetchRequest The fetch request to translate into a URL request.
182
+ @param context The managed object context executing the fetch request.
183
+
184
+ @return An `NSURLRequest` object corresponding to the specified fetch request.
185
+ */
186
+ - (NSMutableURLRequest *)requestForFetchRequest:(NSFetchRequest *)fetchRequest
187
+ withContext:(NSManagedObjectContext *)context;
188
+
189
+ /**
190
+ Returns a URL request object with a given HTTP method for a particular managed object. This method is used in `AFIncrementalStore -newValuesForObjectWithID:withContext:error`.
191
+
192
+ @discussion For example, if a `User` managed object were to be refreshed, this method might return a `GET /users/123` request.
193
+
194
+ @param method The HTTP method of the request.
195
+ @param objectID The object ID for the specified managed object.
196
+ @param context The managed object context for the managed object.
197
+
198
+ @return An `NSURLRequest` object with the provided HTTP method for the resource corresponding to the managed object.
199
+ */
200
+ - (NSMutableURLRequest *)requestWithMethod:(NSString *)method
201
+ pathForObjectWithID:(NSManagedObjectID *)objectID
202
+ withContext:(NSManagedObjectContext *)context;
203
+
204
+ /**
205
+ Returns a URL request object with a given HTTP method for a particular relationship of a given managed object. This method is used in `AFIncrementalStore -newValueForRelationship:forObjectWithID:withContext:error:`.
206
+
207
+ @discussion For example, if a `Department` managed object was attempting to fulfill a fault on the `employees` relationship, this method might return `GET /departments/sales/employees`.
208
+
209
+ @param method The HTTP method of the request.
210
+ @param relationship The relationship of the specifified managed object
211
+ @param objectID The object ID for the specified managed object.
212
+ @param context The managed object context for the managed object.
213
+
214
+ @return An `NSURLRequest` object with the provided HTTP method for the resource or resoures corresponding to the relationship of the managed object.
215
+
216
+ */
217
+ - (NSMutableURLRequest *)requestWithMethod:(NSString *)method
218
+ pathForRelationship:(NSRelationshipDescription *)relationship
219
+ forObjectWithID:(NSManagedObjectID *)objectID
220
+ withContext:(NSManagedObjectContext *)context;
221
+
222
+ @optional
223
+
224
+ ///-----------------------
225
+ /// @name Optional Methods
226
+ ///-----------------------
227
+
228
+ /**
229
+ Returns the attributes representation of an entity from the specified managed object. This method is used to get the attributes of the representation from its managed object.
230
+
231
+ @discussion For example, if the representation sent to `POST /products` or `PUT /products/123` had a `description` field that corresponded with the `productDescription` attribute in its Core Data model, this method would set the value of the `productDescription` field to the value of the `description` key in representation/dictionary.
232
+
233
+ @param attributes The resource representation.
234
+ @param managedObject The `NSManagedObject` for the representation.
235
+
236
+ @return An `NSDictionary` containing the attributes for a representation, based on the given managed object.
237
+ */
238
+ - (NSDictionary *)representationOfAttributes:(NSDictionary *)attributes
239
+ ofManagedObject:(NSManagedObject *)managedObject;
240
+
241
+ /**
242
+
243
+ */
244
+ - (NSMutableURLRequest *)requestForInsertedObject:(NSManagedObject *)insertedObject;
245
+
246
+ /**
247
+
248
+ */
249
+ - (NSMutableURLRequest *)requestForUpdatedObject:(NSManagedObject *)updatedObject;
250
+
251
+ /**
252
+
253
+ */
254
+ - (NSMutableURLRequest *)requestForDeletedObject:(NSManagedObject *)deletedObject;
255
+
256
+ /**
257
+ Returns whether the client should fetch remote attribute values for a particular managed object. This method is consulted when a managed object faults on an attribute, and will call `-requestWithMethod:pathForObjectWithID:withContext:` if `YES`.
258
+
259
+ @param objectID The object ID for the specified managed object.
260
+ @param context The managed object context for the managed object.
261
+
262
+ @return `YES` if an HTTP request should be made, otherwise `NO.
263
+ */
264
+ - (BOOL)shouldFetchRemoteAttributeValuesForObjectWithID:(NSManagedObjectID *)objectID
265
+ inManagedObjectContext:(NSManagedObjectContext *)context;
266
+
267
+ /**
268
+ Returns whether the client should fetch remote relationship values for a particular managed object. This method is consulted when a managed object faults on a particular relationship, and will call `-requestWithMethod:pathForRelationship:forObjectWithID:withContext:` if `YES`.
269
+
270
+ @param relationship The relationship of the specifified managed object
271
+ @param objectID The object ID for the specified managed object.
272
+ @param context The managed object context for the managed object.
273
+
274
+ @return `YES` if an HTTP request should be made, otherwise `NO.
275
+ */
276
+ - (BOOL)shouldFetchRemoteValuesForRelationship:(NSRelationshipDescription *)relationship
277
+ forObjectWithID:(NSManagedObjectID *)objectID
278
+ inManagedObjectContext:(NSManagedObjectContext *)context;
279
+
280
+ @end
281
+
282
+ ///----------------
283
+ /// @name Functions
284
+ ///----------------
285
+
286
+ /**
287
+ There is a bug in Core Data wherein managed object IDs whose reference object is a string beginning with a digit will incorrectly strip any subsequent non-numeric characters from the reference object. This breaks any functionality related to URI representations of the managed object ID, and likely other methods as well. For example, an object ID with a reference object of @"123ABC" would generate one with a URI represenation `coredata://store-UUID/Entity/123`, rather than the expected `coredata://store-UUID/Entity/123ABC`. As a fix, rather than resource identifiers being used directly as reference objects, they are prepended with a non-numeric constant first.
288
+
289
+ Thus, in order to get the resource identifier of a managed object's reference object, you must use the function `AFResourceIdentifierFromReferenceObject()`.
290
+
291
+ See https://github.com/AFNetworking/AFIncrementalStore/issues/82 for more details.
292
+ */
293
+ extern NSString * AFReferenceObjectFromResourceIdentifier(NSString *resourceIdentifier);
294
+
295
+ extern NSString * AFResourceIdentifierFromReferenceObject(id referenceObject);
296
+
297
+ ///----------------
298
+ /// @name Constants
299
+ ///----------------
300
+
301
+ /**
302
+ The name of the exception called when `AFIncrementalStore` or a subclass is attempted to be used, without implementing one of the required methods.
303
+ */
304
+ extern NSString * const AFIncrementalStoreUnimplementedMethodException;
305
+
306
+ ///--------------------
307
+ /// @name Notifications
308
+ ///--------------------
309
+
310
+ /**
311
+ Posted before an HTTP request operation starts.
312
+ The object is the managed object context of the request.
313
+ The notification `userInfo` contains the finished request operation, keyed at `AFIncrementalStoreRequestOperationKey`, as well as the associated persistent store request, if applicable, keyed at `AFIncrementalStorePersistentStoreRequestKey`.
314
+ */
315
+ extern NSString * const AFIncrementalStoreContextWillFetchRemoteValues;
316
+
317
+ /**
318
+
319
+ */
320
+ extern NSString * const AFIncrementalStoreContextWillSaveRemoteValues;
321
+
322
+ /**
323
+ Posted after an HTTP request operation finishes.
324
+ The object is the managed object context of the request.
325
+ The notification `userInfo` contains the finished request operation, keyed at `AFIncrementalStoreRequestOperationKey`, as well as the associated persistent store request, if applicable, keyed at `AFIncrementalStorePersistentStoreRequestKey`.
326
+ */
327
+ extern NSString * const AFIncrementalStoreContextDidFetchRemoteValues;
328
+
329
+ /**
330
+
331
+ */
332
+ extern NSString * const AFIncrementalStoreContextDidSaveRemoteValues;
333
+
334
+ /**
335
+ A key in the `userInfo` dictionary in a `AFIncrementalStoreContextWillFetchRemoteValues` or `AFIncrementalStoreContextDidFetchRemoteValues` notification.
336
+ The corresponding value is an `AFHTTPRequestOperation` object representing the associated request. */
337
+ extern NSString * const AFIncrementalStoreRequestOperationKey;
338
+
339
+ /**
340
+ A key in the `userInfo` dictionary in a `AFIncrementalStoreContextWillFetchRemoteValues` or `AFIncrementalStoreContextDidFetchRemoteValues` notification.
341
+ The corresponding value is an `NSPersistentStoreRequest` object representing the associated fetch or save request. */
342
+ extern NSString * const AFIncrementalStorePersistentStoreRequestKey;
343
+
344
+ extern NSString * const AFIncrementalStoreFetchedObjectsKey;
@@ -0,0 +1,848 @@
1
+ // AFIncrementalStore.m
2
+ //
3
+ // Copyright (c) 2012 Mattt Thompson (http://mattt.me)
4
+ //
5
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ // of this software and associated documentation files (the "Software"), to deal
7
+ // in the Software without restriction, including without limitation the rights
8
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ // copies of the Software, and to permit persons to whom the Software is
10
+ // furnished to do so, subject to the following conditions:
11
+ //
12
+ // The above copyright notice and this permission notice shall be included in
13
+ // all copies or substantial portions of the Software.
14
+ //
15
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ // THE SOFTWARE.
22
+
23
+ #import "AFIncrementalStore.h"
24
+ #import "AFHTTPClient.h"
25
+ #import <objc/runtime.h>
26
+
27
+ NSString * const AFIncrementalStoreUnimplementedMethodException = @"com.alamofire.incremental-store.exceptions.unimplemented-method";
28
+
29
+ NSString * const AFIncrementalStoreContextWillFetchRemoteValues = @"AFIncrementalStoreContextWillFetchRemoteValues";
30
+ NSString * const AFIncrementalStoreContextWillSaveRemoteValues = @"AFIncrementalStoreContextWillSaveRemoteValues";
31
+ NSString * const AFIncrementalStoreContextDidFetchRemoteValues = @"AFIncrementalStoreContextDidFetchRemoteValues";
32
+ NSString * const AFIncrementalStoreContextDidSaveRemoteValues = @"AFIncrementalStoreContextDidSaveRemoteValues";
33
+ NSString * const AFIncrementalStoreRequestOperationKey = @"AFIncrementalStoreRequestOperation";
34
+ NSString * const AFIncrementalStorePersistentStoreRequestKey = @"AFIncrementalStorePersistentStoreRequest";
35
+ NSString * const AFIncrementalStoreFetchedObjectsKey = @"AFIncrementalStoreFetchedObjectsKey";
36
+
37
+ static char kAFResourceIdentifierObjectKey;
38
+
39
+ static NSString * const kAFIncrementalStoreResourceIdentifierAttributeName = @"__af_resourceIdentifier";
40
+ static NSString * const kAFIncrementalStoreLastModifiedAttributeName = @"__af_lastModified";
41
+
42
+ static NSString * const kAFReferenceObjectPrefix = @"__af_";
43
+
44
+ inline NSString * AFReferenceObjectFromResourceIdentifier(NSString *resourceIdentifier) {
45
+ if (!resourceIdentifier) {
46
+ return nil;
47
+ }
48
+
49
+ return [kAFReferenceObjectPrefix stringByAppendingString:resourceIdentifier];
50
+ }
51
+
52
+ inline NSString * AFResourceIdentifierFromReferenceObject(id referenceObject) {
53
+ if (!referenceObject) {
54
+ return nil;
55
+ }
56
+
57
+ NSString *string = [referenceObject description];
58
+ return [string hasPrefix:kAFReferenceObjectPrefix] ? [string substringFromIndex:[kAFReferenceObjectPrefix length]] : string;
59
+ }
60
+
61
+ @interface NSManagedObject (_AFIncrementalStore)
62
+ @property (readwrite, nonatomic, copy, setter = af_setResourceIdentifier:) NSString *af_resourceIdentifier;
63
+ @end
64
+
65
+ @implementation NSManagedObject (_AFIncrementalStore)
66
+ @dynamic af_resourceIdentifier;
67
+
68
+ - (NSString *)af_resourceIdentifier {
69
+ NSString *identifier = (NSString *)objc_getAssociatedObject(self, &kAFResourceIdentifierObjectKey);
70
+
71
+ if (!identifier) {
72
+ if ([self.objectID.persistentStore isKindOfClass:[AFIncrementalStore class]]) {
73
+ id referenceObject = [(AFIncrementalStore *)self.objectID.persistentStore referenceObjectForObjectID:self.objectID];
74
+ if ([referenceObject isKindOfClass:[NSString class]]) {
75
+ return AFResourceIdentifierFromReferenceObject(referenceObject);
76
+ }
77
+ }
78
+ }
79
+
80
+ return identifier;
81
+ }
82
+
83
+ - (void)af_setResourceIdentifier:(NSString *)resourceIdentifier {
84
+ objc_setAssociatedObject(self, &kAFResourceIdentifierObjectKey, resourceIdentifier, OBJC_ASSOCIATION_COPY_NONATOMIC);
85
+ }
86
+
87
+ @end
88
+
89
+ #pragma mark -
90
+
91
+ @implementation AFIncrementalStore {
92
+ @private
93
+ NSCache *_backingObjectIDByObjectID;
94
+ NSMutableDictionary *_registeredObjectIDsByEntityNameAndNestedResourceIdentifier;
95
+ NSPersistentStoreCoordinator *_backingPersistentStoreCoordinator;
96
+ NSManagedObjectContext *_backingManagedObjectContext;
97
+ }
98
+ @synthesize HTTPClient = _HTTPClient;
99
+ @synthesize backingPersistentStoreCoordinator = _backingPersistentStoreCoordinator;
100
+
101
+ + (NSString *)type {
102
+ @throw([NSException exceptionWithName:AFIncrementalStoreUnimplementedMethodException reason:NSLocalizedString(@"Unimplemented method: +type. Must be overridden in a subclass", nil) userInfo:nil]);
103
+ }
104
+
105
+ + (NSManagedObjectModel *)model {
106
+ @throw([NSException exceptionWithName:AFIncrementalStoreUnimplementedMethodException reason:NSLocalizedString(@"Unimplemented method: +model. Must be overridden in a subclass", nil) userInfo:nil]);
107
+ }
108
+
109
+ #pragma mark -
110
+
111
+ - (void)notifyManagedObjectContext:(NSManagedObjectContext *)context
112
+ aboutRequestOperation:(AFHTTPRequestOperation *)operation
113
+ forFetchRequest:(NSFetchRequest *)fetchRequest
114
+ fetchedObjects:(NSArray *)fetchedObjects
115
+ {
116
+ NSString *notificationName = [operation isFinished] ? AFIncrementalStoreContextDidFetchRemoteValues : AFIncrementalStoreContextWillFetchRemoteValues;
117
+
118
+ NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
119
+ [userInfo setObject:operation forKey:AFIncrementalStoreRequestOperationKey];
120
+ [userInfo setObject:fetchRequest forKey:AFIncrementalStorePersistentStoreRequestKey];
121
+ if ([operation isFinished] && fetchedObjects) {
122
+ [userInfo setObject:fetchedObjects forKey:AFIncrementalStoreFetchedObjectsKey];
123
+ }
124
+
125
+ [[NSNotificationCenter defaultCenter] postNotificationName:notificationName object:context userInfo:userInfo];
126
+ }
127
+
128
+ - (void)notifyManagedObjectContext:(NSManagedObjectContext *)context
129
+ aboutRequestOperations:(NSArray *)operations
130
+ forSaveChangesRequest:(NSSaveChangesRequest *)saveChangesRequest
131
+ {
132
+ NSString *notificationName = [[operations lastObject] isFinished] ? AFIncrementalStoreContextDidSaveRemoteValues : AFIncrementalStoreContextWillSaveRemoteValues;
133
+
134
+ NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
135
+ [userInfo setObject:operations forKey:AFIncrementalStoreRequestOperationKey];
136
+ [userInfo setObject:saveChangesRequest forKey:AFIncrementalStorePersistentStoreRequestKey];
137
+
138
+ [[NSNotificationCenter defaultCenter] postNotificationName:notificationName object:context userInfo:userInfo];
139
+ }
140
+
141
+ #pragma mark -
142
+
143
+ - (NSManagedObjectContext *)backingManagedObjectContext {
144
+ if (!_backingManagedObjectContext) {
145
+ _backingManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
146
+ _backingManagedObjectContext.persistentStoreCoordinator = _backingPersistentStoreCoordinator;
147
+ _backingManagedObjectContext.retainsRegisteredObjects = YES;
148
+ }
149
+
150
+ return _backingManagedObjectContext;
151
+ }
152
+
153
+ - (NSManagedObjectID *)objectIDForEntity:(NSEntityDescription *)entity
154
+ withResourceIdentifier:(NSString *)resourceIdentifier
155
+ {
156
+ if (!resourceIdentifier) {
157
+ return nil;
158
+ }
159
+
160
+ NSManagedObjectID *objectID = nil;
161
+ NSMutableDictionary *objectIDsByResourceIdentifier = [_registeredObjectIDsByEntityNameAndNestedResourceIdentifier objectForKey:entity.name];
162
+ if (objectIDsByResourceIdentifier) {
163
+ objectID = [objectIDsByResourceIdentifier objectForKey:resourceIdentifier];
164
+ }
165
+
166
+ if (!objectID) {
167
+ objectID = [self newObjectIDForEntity:entity referenceObject:AFReferenceObjectFromResourceIdentifier(resourceIdentifier)];
168
+ }
169
+
170
+ NSParameterAssert([objectID.entity.name isEqualToString:entity.name]);
171
+
172
+ return objectID;
173
+ }
174
+
175
+ - (NSManagedObjectID *)objectIDForBackingObjectForEntity:(NSEntityDescription *)entity
176
+ withResourceIdentifier:(NSString *)resourceIdentifier
177
+ {
178
+ if (!resourceIdentifier) {
179
+ return nil;
180
+ }
181
+
182
+ NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:[entity name]];
183
+ fetchRequest.resultType = NSManagedObjectIDResultType;
184
+ fetchRequest.fetchLimit = 1;
185
+ fetchRequest.predicate = [NSPredicate predicateWithFormat:@"%K = %@", kAFIncrementalStoreResourceIdentifierAttributeName, resourceIdentifier];
186
+
187
+ __block NSArray *results = nil;
188
+ __block NSError *error = nil;
189
+
190
+ [self.backingPersistentStoreCoordinator lock];
191
+ NSManagedObjectContext *backingContext = [self backingManagedObjectContext];
192
+ [backingContext performBlockAndWait:^{
193
+ results = [backingContext executeFetchRequest:fetchRequest error:&error];
194
+ }];
195
+ [self.backingPersistentStoreCoordinator unlock];
196
+
197
+ if (error) {
198
+ NSLog(@"Error: %@", error);
199
+ return nil;
200
+ }
201
+
202
+ return [results lastObject];
203
+ }
204
+
205
+ - (void)updateBackingObject:(NSManagedObject *)backingObject
206
+ withAttributeAndRelationshipValuesFromManagedObject:(NSManagedObject *)managedObject
207
+ {
208
+ for (NSRelationshipDescription *relationship in [managedObject.entity.relationshipsByName allValues]) {
209
+ id relationshipValue = [managedObject valueForKey:relationship.name];
210
+ if (!relationshipValue) {
211
+ continue;
212
+ }
213
+
214
+ if ([relationship isToMany]) {
215
+ id mutableBackingRelationshipValue = nil;
216
+ if ([relationship isOrdered]) {
217
+ mutableBackingRelationshipValue = [NSMutableOrderedSet orderedSetWithCapacity:[relationshipValue count]];
218
+ } else {
219
+ mutableBackingRelationshipValue = [NSMutableSet setWithCapacity:[relationshipValue count]];
220
+ }
221
+
222
+ for (NSManagedObject *relationshipManagedObject in relationshipValue) {
223
+ if (![[relationshipManagedObject objectID] isTemporaryID]) {
224
+ NSManagedObjectID *backingRelationshipObjectID = [self objectIDForBackingObjectForEntity:relationship.destinationEntity withResourceIdentifier:AFResourceIdentifierFromReferenceObject([self referenceObjectForObjectID:relationshipManagedObject.objectID])];
225
+ if (backingRelationshipObjectID) {
226
+ NSManagedObject *backingRelationshipObject = [backingObject.managedObjectContext existingObjectWithID:backingRelationshipObjectID error:nil];
227
+ if (backingRelationshipObject) {
228
+ [mutableBackingRelationshipValue addObject:backingRelationshipObject];
229
+ }
230
+ }
231
+ }
232
+ }
233
+
234
+ [backingObject setValue:mutableBackingRelationshipValue forKey:relationship.name];
235
+ } else {
236
+ if (![[relationshipValue objectID] isTemporaryID]) {
237
+ NSManagedObjectID *backingRelationshipObjectID = [self objectIDForBackingObjectForEntity:relationship.destinationEntity withResourceIdentifier:AFResourceIdentifierFromReferenceObject([self referenceObjectForObjectID:[relationshipValue objectID]])];
238
+ if (backingRelationshipObjectID) {
239
+ NSManagedObject *backingRelationshipObject = [backingObject.managedObjectContext existingObjectWithID:backingRelationshipObjectID error:nil];
240
+ [backingObject setValue:backingRelationshipObject forKey:relationship.name];
241
+ }
242
+ }
243
+ }
244
+ }
245
+
246
+ [backingObject setValuesForKeysWithDictionary:[managedObject dictionaryWithValuesForKeys:[managedObject.entity.attributesByName allKeys]]];
247
+ }
248
+
249
+ #pragma mark -
250
+
251
+ - (BOOL)insertOrUpdateObjectsFromRepresentations:(id)representationOrArrayOfRepresentations
252
+ ofEntity:(NSEntityDescription *)entity
253
+ fromResponse:(NSHTTPURLResponse *)response
254
+ withContext:(NSManagedObjectContext *)context
255
+ error:(NSError *__autoreleasing *)error
256
+ completionBlock:(void (^)(NSArray *managedObjects, NSArray *backingObjects))completionBlock
257
+ {
258
+ NSParameterAssert([representationOrArrayOfRepresentations isKindOfClass:[NSArray class]] || [representationOrArrayOfRepresentations isKindOfClass:[NSDictionary class]]);
259
+
260
+ if ([representationOrArrayOfRepresentations count] == 0) {
261
+ if (completionBlock) {
262
+ completionBlock([NSArray array], [NSArray array]);
263
+ }
264
+
265
+ return NO;
266
+ }
267
+
268
+ NSManagedObjectContext *backingContext = [self backingManagedObjectContext];
269
+ NSString *lastModified = [[response allHeaderFields] valueForKey:@"Last-Modified"];
270
+
271
+ NSArray *representations = nil;
272
+ if ([representationOrArrayOfRepresentations isKindOfClass:[NSArray class]]) {
273
+ representations = representationOrArrayOfRepresentations;
274
+ } else if ([representationOrArrayOfRepresentations isKindOfClass:[NSDictionary class]]) {
275
+ representations = [NSArray arrayWithObject:representationOrArrayOfRepresentations];
276
+ }
277
+
278
+ NSUInteger numberOfRepresentations = [representations count];
279
+ NSMutableArray *mutableManagedObjects = [NSMutableArray arrayWithCapacity:numberOfRepresentations];
280
+ NSMutableArray *mutableBackingObjects = [NSMutableArray arrayWithCapacity:numberOfRepresentations];
281
+
282
+ for (NSDictionary *representation in representations) {
283
+ NSString *resourceIdentifier = [self.HTTPClient resourceIdentifierForRepresentation:representation ofEntity:entity fromResponse:response];
284
+ NSDictionary *attributes = [self.HTTPClient attributesForRepresentation:representation ofEntity:entity fromResponse:response];
285
+
286
+ __block NSManagedObject *managedObject = nil;
287
+ [context performBlockAndWait:^{
288
+ managedObject = [context existingObjectWithID:[self objectIDForEntity:entity withResourceIdentifier:resourceIdentifier] error:nil];
289
+ }];
290
+
291
+ [managedObject setValuesForKeysWithDictionary:attributes];
292
+
293
+ NSManagedObjectID *backingObjectID = [self objectIDForBackingObjectForEntity:entity withResourceIdentifier:resourceIdentifier];
294
+ __block NSManagedObject *backingObject = nil;
295
+ [backingContext performBlockAndWait:^{
296
+ if (backingObjectID) {
297
+ backingObject = [backingContext existingObjectWithID:backingObjectID error:nil];
298
+ } else {
299
+ backingObject = [NSEntityDescription insertNewObjectForEntityForName:entity.name inManagedObjectContext:backingContext];
300
+ [backingObject.managedObjectContext obtainPermanentIDsForObjects:[NSArray arrayWithObject:backingObject] error:nil];
301
+ }
302
+ }];
303
+ [backingObject setValue:resourceIdentifier forKey:kAFIncrementalStoreResourceIdentifierAttributeName];
304
+ [backingObject setValue:lastModified forKey:kAFIncrementalStoreLastModifiedAttributeName];
305
+ [backingObject setValuesForKeysWithDictionary:attributes];
306
+
307
+ if (!backingObjectID) {
308
+ [context insertObject:managedObject];
309
+ }
310
+
311
+ NSDictionary *relationshipRepresentations = [self.HTTPClient representationsForRelationshipsFromRepresentation:representation ofEntity:entity fromResponse:response];
312
+ for (NSString *relationshipName in relationshipRepresentations) {
313
+ NSRelationshipDescription *relationship = [[entity relationshipsByName] valueForKey:relationshipName];
314
+ id relationshipRepresentation = [relationshipRepresentations objectForKey:relationshipName];
315
+ if (!relationship || (relationship.isOptional && (!relationshipRepresentation || [relationshipRepresentation isEqual:[NSNull null]]))) {
316
+ continue;
317
+ }
318
+
319
+ if (!relationshipRepresentation || [relationshipRepresentation isEqual:[NSNull null]] || [relationshipRepresentation count] == 0) {
320
+ [managedObject setValue:nil forKey:relationshipName];
321
+ [backingObject setValue:nil forKey:relationshipName];
322
+ continue;
323
+ }
324
+
325
+ [self insertOrUpdateObjectsFromRepresentations:relationshipRepresentation ofEntity:relationship.destinationEntity fromResponse:response withContext:context error:error completionBlock:^(NSArray *managedObjects, NSArray *backingObjects) {
326
+ if ([relationship isToMany]) {
327
+ if ([relationship isOrdered]) {
328
+ [managedObject setValue:[NSOrderedSet orderedSetWithArray:managedObjects] forKey:relationship.name];
329
+ [backingObject setValue:[NSOrderedSet orderedSetWithArray:backingObjects] forKey:relationship.name];
330
+ } else {
331
+ [managedObject setValue:[NSSet setWithArray:managedObjects] forKey:relationship.name];
332
+ [backingObject setValue:[NSSet setWithArray:backingObjects] forKey:relationship.name];
333
+ }
334
+ } else {
335
+ [managedObject setValue:[managedObjects lastObject] forKey:relationship.name];
336
+ [backingObject setValue:[backingObjects lastObject] forKey:relationship.name];
337
+ }
338
+ }];
339
+ }
340
+
341
+ [mutableManagedObjects addObject:managedObject];
342
+ [mutableBackingObjects addObject:backingObject];
343
+ }
344
+
345
+ if (completionBlock) {
346
+ completionBlock(mutableManagedObjects, mutableBackingObjects);
347
+ }
348
+
349
+ return YES;
350
+ }
351
+
352
+ - (id)executeFetchRequest:(NSFetchRequest *)fetchRequest
353
+ withContext:(NSManagedObjectContext *)context
354
+ error:(NSError *__autoreleasing *)error
355
+ {
356
+ NSURLRequest *request = [self.HTTPClient requestForFetchRequest:fetchRequest withContext:context];
357
+ if ([request URL]) {
358
+ AFHTTPRequestOperation *operation = [self.HTTPClient HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
359
+ id representationOrArrayOfRepresentations = [self.HTTPClient representationOrArrayOfRepresentationsOfEntity:fetchRequest.entity fromResponseObject:responseObject];
360
+
361
+ NSManagedObjectContext *childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
362
+ childContext.parentContext = context;
363
+ childContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
364
+
365
+ [childContext performBlockAndWait:^{
366
+ [self insertOrUpdateObjectsFromRepresentations:representationOrArrayOfRepresentations ofEntity:fetchRequest.entity fromResponse:operation.response withContext:childContext error:error completionBlock:^(NSArray *managedObjects, NSArray *backingObjects) {
367
+
368
+ NSSet *childObjects = [childContext registeredObjects];
369
+
370
+ if (![[self backingManagedObjectContext] save:error] || ![childContext save:error]) {
371
+ @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:[*error localizedFailureReason] userInfo:[NSDictionary dictionaryWithObject:*error forKey:NSUnderlyingErrorKey]];
372
+ }
373
+
374
+ for (NSManagedObject *childObject in childObjects) {
375
+ NSManagedObject *parentObject = [context objectWithID:childObject.objectID];
376
+ [parentObject.managedObjectContext refreshObject:parentObject mergeChanges:NO];
377
+ }
378
+
379
+ [context performBlockAndWait:^{
380
+ for (NSManagedObject *childObject in childObjects) {
381
+ NSManagedObject *parentObject = [context objectWithID:childObject.objectID];
382
+ [parentObject willChangeValueForKey:@"self"];
383
+ [context refreshObject:parentObject mergeChanges:NO];
384
+ [parentObject didChangeValueForKey:@"self"];
385
+ }
386
+ }];
387
+
388
+ NSMutableArray *fetchedObjects = [[NSMutableArray alloc] initWithCapacity:[managedObjects count]];
389
+ for (NSManagedObject *managedObject in managedObjects) {
390
+ NSManagedObject *fetchedObject = [context existingObjectWithID:managedObject.objectID error:NULL];
391
+ if (fetchedObject) {
392
+ [fetchedObjects addObject:fetchedObject];
393
+ }
394
+ }
395
+ [fetchedObjects sortUsingDescriptors:fetchRequest.sortDescriptors];
396
+
397
+ [self notifyManagedObjectContext:context aboutRequestOperation:operation forFetchRequest:fetchRequest fetchedObjects:fetchedObjects];
398
+ }];
399
+ }];
400
+ } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
401
+ NSLog(@"Error: %@", error);
402
+ [self notifyManagedObjectContext:context aboutRequestOperation:operation forFetchRequest:fetchRequest fetchedObjects:nil];
403
+ }];
404
+
405
+ [self notifyManagedObjectContext:context aboutRequestOperation:operation forFetchRequest:fetchRequest fetchedObjects:nil];
406
+ [self.HTTPClient enqueueHTTPRequestOperation:operation];
407
+ }
408
+
409
+ NSManagedObjectContext *backingContext = [self backingManagedObjectContext];
410
+ NSFetchRequest *backingFetchRequest = [fetchRequest copy];
411
+ backingFetchRequest.entity = [NSEntityDescription entityForName:fetchRequest.entityName inManagedObjectContext:backingContext];
412
+
413
+ switch (fetchRequest.resultType) {
414
+ case NSManagedObjectResultType: {
415
+ backingFetchRequest.resultType = NSDictionaryResultType;
416
+ backingFetchRequest.propertiesToFetch = [NSArray arrayWithObject:kAFIncrementalStoreResourceIdentifierAttributeName];
417
+ NSArray *results = [backingContext executeFetchRequest:backingFetchRequest error:error];
418
+
419
+ NSMutableArray *mutableObjects = [NSMutableArray arrayWithCapacity:[results count]];
420
+ for (NSString *resourceIdentifier in [results valueForKeyPath:kAFIncrementalStoreResourceIdentifierAttributeName]) {
421
+ NSManagedObjectID *objectID = [self objectIDForEntity:fetchRequest.entity withResourceIdentifier:resourceIdentifier];
422
+ NSManagedObject *object = [context objectWithID:objectID];
423
+ object.af_resourceIdentifier = resourceIdentifier;
424
+ [mutableObjects addObject:object];
425
+ }
426
+
427
+ return mutableObjects;
428
+ }
429
+ case NSManagedObjectIDResultType: {
430
+ NSArray *backingObjectIDs = [backingContext executeFetchRequest:backingFetchRequest error:error];
431
+ NSMutableArray *managedObjectIDs = [NSMutableArray arrayWithCapacity:[backingObjectIDs count]];
432
+
433
+ for (NSManagedObjectID *backingObjectID in backingObjectIDs) {
434
+ NSManagedObject *backingObject = [backingContext objectWithID:backingObjectID];
435
+ NSString *resourceID = [backingObject valueForKey:kAFIncrementalStoreResourceIdentifierAttributeName];
436
+ [managedObjectIDs addObject:[self objectIDForEntity:fetchRequest.entity withResourceIdentifier:resourceID]];
437
+ }
438
+
439
+ return managedObjectIDs;
440
+ }
441
+ case NSDictionaryResultType:
442
+ case NSCountResultType:
443
+ return [backingContext executeFetchRequest:backingFetchRequest error:error];
444
+ default:
445
+ return nil;
446
+ }
447
+ }
448
+
449
+ - (id)executeSaveChangesRequest:(NSSaveChangesRequest *)saveChangesRequest
450
+ withContext:(NSManagedObjectContext *)context
451
+ error:(NSError *__autoreleasing *)error
452
+ {
453
+ NSMutableArray *mutableOperations = [NSMutableArray array];
454
+ NSManagedObjectContext *backingContext = [self backingManagedObjectContext];
455
+
456
+ if ([self.HTTPClient respondsToSelector:@selector(requestForInsertedObject:)]) {
457
+ for (NSManagedObject *insertedObject in [saveChangesRequest insertedObjects]) {
458
+ NSURLRequest *request = [self.HTTPClient requestForInsertedObject:insertedObject];
459
+ if (!request) {
460
+ [backingContext performBlockAndWait:^{
461
+ CFUUIDRef UUID = CFUUIDCreate(NULL);
462
+ NSString *resourceIdentifier = (__bridge_transfer NSString *)CFUUIDCreateString(NULL, UUID);
463
+ CFRelease(UUID);
464
+
465
+ NSManagedObject *backingObject = [NSEntityDescription insertNewObjectForEntityForName:insertedObject.entity.name inManagedObjectContext:backingContext];
466
+ [backingObject.managedObjectContext obtainPermanentIDsForObjects:[NSArray arrayWithObject:backingObject] error:nil];
467
+ [backingObject setValue:resourceIdentifier forKey:kAFIncrementalStoreResourceIdentifierAttributeName];
468
+ [self updateBackingObject:backingObject withAttributeAndRelationshipValuesFromManagedObject:insertedObject];
469
+ [backingContext save:nil];
470
+ }];
471
+
472
+ [insertedObject willChangeValueForKey:@"objectID"];
473
+ [context obtainPermanentIDsForObjects:[NSArray arrayWithObject:insertedObject] error:nil];
474
+ [insertedObject didChangeValueForKey:@"objectID"];
475
+ continue;
476
+ }
477
+
478
+ AFHTTPRequestOperation *operation = [self.HTTPClient HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
479
+ NSString *resourceIdentifier = [self.HTTPClient resourceIdentifierForRepresentation:responseObject ofEntity:[insertedObject entity] fromResponse:operation.response];
480
+ NSManagedObjectID *objectID = [self objectIDForEntity:[insertedObject entity] withResourceIdentifier:resourceIdentifier];
481
+ insertedObject.af_resourceIdentifier = resourceIdentifier;
482
+ [insertedObject setValuesForKeysWithDictionary:[self.HTTPClient attributesForRepresentation:responseObject ofEntity:insertedObject.entity fromResponse:operation.response]];
483
+
484
+ [backingContext performBlockAndWait:^{
485
+ __block NSManagedObject *backingObject = nil;
486
+ if (objectID) {
487
+ [backingContext performBlockAndWait:^{
488
+ backingObject = [backingContext existingObjectWithID:objectID error:nil];
489
+ }];
490
+ }
491
+
492
+ if (!backingObject) {
493
+ backingObject = [NSEntityDescription insertNewObjectForEntityForName:insertedObject.entity.name inManagedObjectContext:backingContext];
494
+ [backingObject.managedObjectContext obtainPermanentIDsForObjects:[NSArray arrayWithObject:backingObject] error:nil];
495
+ }
496
+
497
+ [backingObject setValue:resourceIdentifier forKey:kAFIncrementalStoreResourceIdentifierAttributeName];
498
+ [self updateBackingObject:backingObject withAttributeAndRelationshipValuesFromManagedObject:insertedObject];
499
+ [backingContext save:nil];
500
+ }];
501
+
502
+ [insertedObject willChangeValueForKey:@"objectID"];
503
+ [context obtainPermanentIDsForObjects:[NSArray arrayWithObject:insertedObject] error:nil];
504
+ [insertedObject didChangeValueForKey:@"objectID"];
505
+
506
+ [context refreshObject:insertedObject mergeChanges:NO];
507
+ } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
508
+ NSLog(@"Insert Error: %@", error);
509
+ }];
510
+
511
+ [mutableOperations addObject:operation];
512
+ }
513
+ }
514
+
515
+ if ([self.HTTPClient respondsToSelector:@selector(requestForUpdatedObject:)]) {
516
+ for (NSManagedObject *updatedObject in [saveChangesRequest updatedObjects]) {
517
+ NSManagedObjectID *backingObjectID = [self objectIDForBackingObjectForEntity:[updatedObject entity] withResourceIdentifier:AFResourceIdentifierFromReferenceObject([self referenceObjectForObjectID:updatedObject.objectID])];
518
+
519
+ NSURLRequest *request = [self.HTTPClient requestForUpdatedObject:updatedObject];
520
+ if (!request) {
521
+ [backingContext performBlockAndWait:^{
522
+ NSManagedObject *backingObject = [backingContext existingObjectWithID:backingObjectID error:nil];
523
+ [self updateBackingObject:backingObject withAttributeAndRelationshipValuesFromManagedObject:updatedObject];
524
+ [backingContext save:nil];
525
+ }];
526
+ continue;
527
+ }
528
+
529
+ AFHTTPRequestOperation *operation = [self.HTTPClient HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
530
+ [updatedObject setValuesForKeysWithDictionary:[self.HTTPClient attributesForRepresentation:responseObject ofEntity:updatedObject.entity fromResponse:operation.response]];
531
+
532
+ [backingContext performBlockAndWait:^{
533
+ NSManagedObject *backingObject = [backingContext existingObjectWithID:backingObjectID error:nil];
534
+ [self updateBackingObject:backingObject withAttributeAndRelationshipValuesFromManagedObject:updatedObject];
535
+ [backingContext save:nil];
536
+ }];
537
+
538
+ [context refreshObject:updatedObject mergeChanges:NO];
539
+ } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
540
+ NSLog(@"Update Error: %@", error);
541
+ [context refreshObject:updatedObject mergeChanges:NO];
542
+ }];
543
+
544
+ [mutableOperations addObject:operation];
545
+ }
546
+ }
547
+
548
+ if ([self.HTTPClient respondsToSelector:@selector(requestForDeletedObject:)]) {
549
+ for (NSManagedObject *deletedObject in [saveChangesRequest deletedObjects]) {
550
+ NSManagedObjectID *backingObjectID = [self objectIDForBackingObjectForEntity:[deletedObject entity] withResourceIdentifier:AFResourceIdentifierFromReferenceObject([self referenceObjectForObjectID:deletedObject.objectID])];
551
+
552
+ NSURLRequest *request = [self.HTTPClient requestForDeletedObject:deletedObject];
553
+ if (!request) {
554
+ [backingContext performBlockAndWait:^{
555
+ NSManagedObject *backingObject = [backingContext existingObjectWithID:backingObjectID error:nil];
556
+ [backingContext deleteObject:backingObject];
557
+ [backingContext save:nil];
558
+ }];
559
+ continue;
560
+ }
561
+
562
+ AFHTTPRequestOperation *operation = [self.HTTPClient HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
563
+ [backingContext performBlockAndWait:^{
564
+ NSManagedObject *backingObject = [backingContext existingObjectWithID:backingObjectID error:nil];
565
+ [backingContext deleteObject:backingObject];
566
+ [backingContext save:nil];
567
+ }];
568
+ } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
569
+ NSLog(@"Delete Error: %@", error);
570
+ }];
571
+
572
+ [mutableOperations addObject:operation];
573
+ }
574
+ }
575
+
576
+ // NSManagedObjectContext removes object references from an NSSaveChangesRequest as each object is saved, so create a copy of the original in order to send useful information in AFIncrementalStoreContextDidSaveRemoteValues notification.
577
+ NSSaveChangesRequest *saveChangesRequestCopy = [[NSSaveChangesRequest alloc] initWithInsertedObjects:[saveChangesRequest.insertedObjects copy] updatedObjects:[saveChangesRequest.updatedObjects copy] deletedObjects:[saveChangesRequest.deletedObjects copy] lockedObjects:[saveChangesRequest.lockedObjects copy]];
578
+
579
+ [self notifyManagedObjectContext:context aboutRequestOperations:mutableOperations forSaveChangesRequest:saveChangesRequestCopy];
580
+
581
+ [self.HTTPClient enqueueBatchOfHTTPRequestOperations:mutableOperations progressBlock:nil completionBlock:^(NSArray *operations) {
582
+ [self notifyManagedObjectContext:context aboutRequestOperations:operations forSaveChangesRequest:saveChangesRequestCopy];
583
+ }];
584
+
585
+ return [NSArray array];
586
+ }
587
+
588
+ #pragma mark - NSIncrementalStore
589
+
590
+ - (BOOL)loadMetadata:(NSError *__autoreleasing *)error {
591
+ if (!_backingObjectIDByObjectID) {
592
+ NSMutableDictionary *mutableMetadata = [NSMutableDictionary dictionary];
593
+ [mutableMetadata setValue:[[NSProcessInfo processInfo] globallyUniqueString] forKey:NSStoreUUIDKey];
594
+ [mutableMetadata setValue:NSStringFromClass([self class]) forKey:NSStoreTypeKey];
595
+ [self setMetadata:mutableMetadata];
596
+
597
+ _backingObjectIDByObjectID = [[NSCache alloc] init];
598
+ _registeredObjectIDsByEntityNameAndNestedResourceIdentifier = [[NSMutableDictionary alloc] init];
599
+
600
+ NSManagedObjectModel *model = [self.persistentStoreCoordinator.managedObjectModel copy];
601
+ for (NSEntityDescription *entity in model.entities) {
602
+ // Don't add properties for sub-entities, as they already exist in the super-entity
603
+ if ([entity superentity]) {
604
+ continue;
605
+ }
606
+
607
+ NSAttributeDescription *resourceIdentifierProperty = [[NSAttributeDescription alloc] init];
608
+ [resourceIdentifierProperty setName:kAFIncrementalStoreResourceIdentifierAttributeName];
609
+ [resourceIdentifierProperty setAttributeType:NSStringAttributeType];
610
+ [resourceIdentifierProperty setIndexed:YES];
611
+
612
+ NSAttributeDescription *lastModifiedProperty = [[NSAttributeDescription alloc] init];
613
+ [lastModifiedProperty setName:kAFIncrementalStoreLastModifiedAttributeName];
614
+ [lastModifiedProperty setAttributeType:NSStringAttributeType];
615
+ [lastModifiedProperty setIndexed:NO];
616
+
617
+ [entity setProperties:[entity.properties arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:resourceIdentifierProperty, lastModifiedProperty, nil]]];
618
+ }
619
+
620
+ _backingPersistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
621
+
622
+ return YES;
623
+ } else {
624
+ return NO;
625
+ }
626
+ }
627
+
628
+ - (NSArray *)obtainPermanentIDsForObjects:(NSArray *)array error:(NSError **)error {
629
+ NSMutableArray *mutablePermanentIDs = [NSMutableArray arrayWithCapacity:[array count]];
630
+ for (NSManagedObject *managedObject in array) {
631
+ NSManagedObjectID *managedObjectID = managedObject.objectID;
632
+ if ([managedObjectID isTemporaryID] && managedObject.af_resourceIdentifier) {
633
+ NSManagedObjectID *objectID = [self objectIDForEntity:managedObject.entity withResourceIdentifier:managedObject.af_resourceIdentifier];
634
+ [mutablePermanentIDs addObject:objectID];
635
+ } else {
636
+ [mutablePermanentIDs addObject:managedObjectID];
637
+ }
638
+ }
639
+
640
+ return mutablePermanentIDs;
641
+ }
642
+
643
+ - (id)executeRequest:(NSPersistentStoreRequest *)persistentStoreRequest
644
+ withContext:(NSManagedObjectContext *)context
645
+ error:(NSError *__autoreleasing *)error
646
+ {
647
+ if (persistentStoreRequest.requestType == NSFetchRequestType) {
648
+ return [self executeFetchRequest:(NSFetchRequest *)persistentStoreRequest withContext:context error:error];
649
+ } else if (persistentStoreRequest.requestType == NSSaveRequestType) {
650
+ return [self executeSaveChangesRequest:(NSSaveChangesRequest *)persistentStoreRequest withContext:context error:error];
651
+ } else {
652
+ NSMutableDictionary *mutableUserInfo = [NSMutableDictionary dictionary];
653
+ [mutableUserInfo setValue:[NSString stringWithFormat:NSLocalizedString(@"Unsupported NSFetchRequestResultType, %d", nil), persistentStoreRequest.requestType] forKey:NSLocalizedDescriptionKey];
654
+ if (error) {
655
+ *error = [[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:0 userInfo:mutableUserInfo];
656
+ }
657
+
658
+ return nil;
659
+ }
660
+ }
661
+
662
+ - (NSIncrementalStoreNode *)newValuesForObjectWithID:(NSManagedObjectID *)objectID
663
+ withContext:(NSManagedObjectContext *)context
664
+ error:(NSError *__autoreleasing *)error
665
+ {
666
+ NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:[[objectID entity] name]];
667
+ fetchRequest.resultType = NSDictionaryResultType;
668
+ fetchRequest.fetchLimit = 1;
669
+ fetchRequest.includesSubentities = NO;
670
+
671
+ NSArray *attributes = [[[NSEntityDescription entityForName:fetchRequest.entityName inManagedObjectContext:context] attributesByName] allValues];
672
+ NSArray *intransientAttributes = [attributes filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"isTransient == NO"]];
673
+ fetchRequest.propertiesToFetch = [[intransientAttributes valueForKeyPath:@"name"] arrayByAddingObject:kAFIncrementalStoreLastModifiedAttributeName];
674
+
675
+ fetchRequest.predicate = [NSPredicate predicateWithFormat:@"%K = %@", kAFIncrementalStoreResourceIdentifierAttributeName, AFResourceIdentifierFromReferenceObject([self referenceObjectForObjectID:objectID])];
676
+
677
+ __block NSArray *results;
678
+ NSManagedObjectContext *backingContext = [self backingManagedObjectContext];
679
+ [backingContext performBlockAndWait:^{
680
+ results = [backingContext executeFetchRequest:fetchRequest error:error];
681
+ }];
682
+
683
+ NSDictionary *attributeValues = [results lastObject] ?: [NSDictionary dictionary];
684
+ NSIncrementalStoreNode *node = [[NSIncrementalStoreNode alloc] initWithObjectID:objectID withValues:attributeValues version:1];
685
+
686
+ if ([self.HTTPClient respondsToSelector:@selector(shouldFetchRemoteAttributeValuesForObjectWithID:inManagedObjectContext:)] && [self.HTTPClient shouldFetchRemoteAttributeValuesForObjectWithID:objectID inManagedObjectContext:context]) {
687
+ if (attributeValues) {
688
+ NSManagedObjectContext *childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
689
+ childContext.parentContext = context;
690
+ childContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
691
+
692
+ NSMutableURLRequest *request = [self.HTTPClient requestWithMethod:@"GET" pathForObjectWithID:objectID withContext:context];
693
+ NSString *lastModified = [attributeValues objectForKey:kAFIncrementalStoreLastModifiedAttributeName];
694
+ if (lastModified) {
695
+ [request setValue:lastModified forHTTPHeaderField:@"Last-Modified"];
696
+ }
697
+
698
+ if ([request URL]) {
699
+ if ([attributeValues valueForKey:kAFIncrementalStoreLastModifiedAttributeName]) {
700
+ [request setValue:[[attributeValues valueForKey:kAFIncrementalStoreLastModifiedAttributeName] description] forHTTPHeaderField:@"If-Modified-Since"];
701
+ }
702
+
703
+ AFHTTPRequestOperation *operation = [self.HTTPClient HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, NSDictionary *representation) {
704
+ NSManagedObject *managedObject = [childContext existingObjectWithID:objectID error:error];
705
+
706
+ NSMutableDictionary *mutableAttributeValues = [attributeValues mutableCopy];
707
+ [mutableAttributeValues addEntriesFromDictionary:[self.HTTPClient attributesForRepresentation:representation ofEntity:managedObject.entity fromResponse:operation.response]];
708
+ [mutableAttributeValues removeObjectForKey:kAFIncrementalStoreLastModifiedAttributeName];
709
+ [managedObject setValuesForKeysWithDictionary:mutableAttributeValues];
710
+
711
+ NSManagedObjectID *backingObjectID = [self objectIDForBackingObjectForEntity:[objectID entity] withResourceIdentifier:AFResourceIdentifierFromReferenceObject([self referenceObjectForObjectID:objectID])];
712
+ NSManagedObject *backingObject = [[self backingManagedObjectContext] existingObjectWithID:backingObjectID error:nil];
713
+ [backingObject setValuesForKeysWithDictionary:mutableAttributeValues];
714
+
715
+ NSString *lastModified = [[operation.response allHeaderFields] valueForKey:@"Last-Modified"];
716
+ if (lastModified) {
717
+ [backingObject setValue:lastModified forKey:kAFIncrementalStoreLastModifiedAttributeName];
718
+ }
719
+
720
+ id observer = [[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification object:childContext queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
721
+ [context mergeChangesFromContextDidSaveNotification:note];
722
+ }];
723
+
724
+ [childContext performBlockAndWait:^{
725
+ if (![[self backingManagedObjectContext] save:error] || ![childContext save:error]) {
726
+ @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:[*error localizedFailureReason] userInfo:[NSDictionary dictionaryWithObject:*error forKey:NSUnderlyingErrorKey]];
727
+ }
728
+ }];
729
+
730
+ [[NSNotificationCenter defaultCenter] removeObserver:observer];
731
+ } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
732
+ NSLog(@"Error: %@, %@", operation, error);
733
+ }];
734
+
735
+ [self.HTTPClient enqueueHTTPRequestOperation:operation];
736
+ }
737
+ }
738
+ }
739
+
740
+ return node;
741
+ }
742
+
743
+ - (id)newValueForRelationship:(NSRelationshipDescription *)relationship
744
+ forObjectWithID:(NSManagedObjectID *)objectID
745
+ withContext:(NSManagedObjectContext *)context
746
+ error:(NSError *__autoreleasing *)error
747
+ {
748
+ if ([self.HTTPClient respondsToSelector:@selector(shouldFetchRemoteValuesForRelationship:forObjectWithID:inManagedObjectContext:)] && [self.HTTPClient shouldFetchRemoteValuesForRelationship:relationship forObjectWithID:objectID inManagedObjectContext:context]) {
749
+ NSURLRequest *request = [self.HTTPClient requestWithMethod:@"GET" pathForRelationship:relationship forObjectWithID:objectID withContext:context];
750
+
751
+ if ([request URL] && ![[context existingObjectWithID:objectID error:nil] hasChanges]) {
752
+ NSManagedObjectContext *childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
753
+ childContext.parentContext = context;
754
+ childContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
755
+
756
+ AFHTTPRequestOperation *operation = [self.HTTPClient HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
757
+ id representationOrArrayOfRepresentations = [self.HTTPClient representationOrArrayOfRepresentationsOfEntity:relationship.entity fromResponseObject:responseObject];
758
+
759
+ [childContext performBlockAndWait:^{
760
+ [self insertOrUpdateObjectsFromRepresentations:representationOrArrayOfRepresentations ofEntity:relationship.destinationEntity fromResponse:operation.response withContext:childContext error:error completionBlock:^(NSArray *managedObjects, NSArray *backingObjects) {
761
+ NSManagedObject *managedObject = [childContext objectWithID:objectID];
762
+ NSManagedObject *backingObject = [[self backingManagedObjectContext] existingObjectWithID:objectID error:nil];
763
+
764
+ if ([relationship isToMany]) {
765
+ if ([relationship isOrdered]) {
766
+ [managedObject setValue:[NSOrderedSet orderedSetWithArray:managedObjects] forKey:relationship.name];
767
+ [backingObject setValue:[NSOrderedSet orderedSetWithArray:backingObjects] forKey:relationship.name];
768
+ } else {
769
+ [managedObject setValue:[NSSet setWithArray:managedObjects] forKey:relationship.name];
770
+ [backingObject setValue:[NSSet setWithArray:backingObjects] forKey:relationship.name];
771
+ }
772
+ } else {
773
+ [managedObject setValue:[managedObjects lastObject] forKey:relationship.name];
774
+ [backingObject setValue:[backingObjects lastObject] forKey:relationship.name];
775
+ }
776
+
777
+ id observer = [[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification object:childContext queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
778
+ [context mergeChangesFromContextDidSaveNotification:note];
779
+ }];
780
+
781
+ if (![[self backingManagedObjectContext] save:error] || ![childContext save:error]) {
782
+ @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:[*error localizedFailureReason] userInfo:[NSDictionary dictionaryWithObject:*error forKey:NSUnderlyingErrorKey]];
783
+ }
784
+
785
+ [[NSNotificationCenter defaultCenter] removeObserver:observer];
786
+ }];
787
+ }];
788
+ } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
789
+ NSLog(@"Error: %@, %@", operation, error);
790
+ }];
791
+
792
+ [self.HTTPClient enqueueHTTPRequestOperation:operation];
793
+ }
794
+ }
795
+
796
+ NSManagedObjectID *backingObjectID = [self objectIDForBackingObjectForEntity:[objectID entity] withResourceIdentifier:AFResourceIdentifierFromReferenceObject([self referenceObjectForObjectID:objectID])];
797
+ NSManagedObject *backingObject = (backingObjectID == nil) ? nil : [[self backingManagedObjectContext] existingObjectWithID:backingObjectID error:nil];
798
+
799
+ if (backingObject && ![backingObject hasChanges]) {
800
+ id backingRelationshipObject = [backingObject valueForKeyPath:relationship.name];
801
+ if ([relationship isToMany]) {
802
+ NSMutableArray *mutableObjects = [NSMutableArray arrayWithCapacity:[backingRelationshipObject count]];
803
+ for (NSString *resourceIdentifier in [backingRelationshipObject valueForKeyPath:kAFIncrementalStoreResourceIdentifierAttributeName]) {
804
+ NSManagedObjectID *objectID = [self objectIDForEntity:relationship.destinationEntity withResourceIdentifier:resourceIdentifier];
805
+ [mutableObjects addObject:objectID];
806
+ }
807
+
808
+ return mutableObjects;
809
+ } else {
810
+ NSString *resourceIdentifier = [backingRelationshipObject valueForKeyPath:kAFIncrementalStoreResourceIdentifierAttributeName];
811
+ NSManagedObjectID *objectID = [self objectIDForEntity:relationship.destinationEntity withResourceIdentifier:resourceIdentifier];
812
+
813
+ return objectID ?: [NSNull null];
814
+ }
815
+ } else {
816
+ if ([relationship isToMany]) {
817
+ return [NSArray array];
818
+ } else {
819
+ return [NSNull null];
820
+ }
821
+ }
822
+ }
823
+
824
+ - (void)managedObjectContextDidRegisterObjectsWithIDs:(NSArray *)objectIDs {
825
+ [super managedObjectContextDidRegisterObjectsWithIDs:objectIDs];
826
+
827
+ for (NSManagedObjectID *objectID in objectIDs) {
828
+ id referenceObject = [self referenceObjectForObjectID:objectID];
829
+ if (!referenceObject) {
830
+ continue;
831
+ }
832
+
833
+ NSMutableDictionary *objectIDsByResourceIdentifier = [_registeredObjectIDsByEntityNameAndNestedResourceIdentifier objectForKey:objectID.entity.name] ?: [NSMutableDictionary dictionary];
834
+ [objectIDsByResourceIdentifier setObject:objectID forKey:AFResourceIdentifierFromReferenceObject(referenceObject)];
835
+
836
+ [_registeredObjectIDsByEntityNameAndNestedResourceIdentifier setObject:objectIDsByResourceIdentifier forKey:objectID.entity.name];
837
+ }
838
+ }
839
+
840
+ - (void)managedObjectContextDidUnregisterObjectsWithIDs:(NSArray *)objectIDs {
841
+ [super managedObjectContextDidUnregisterObjectsWithIDs:objectIDs];
842
+
843
+ for (NSManagedObjectID *objectID in objectIDs) {
844
+ [[_registeredObjectIDsByEntityNameAndNestedResourceIdentifier objectForKey:objectID.entity.name] removeObjectForKey:AFResourceIdentifierFromReferenceObject([self referenceObjectForObjectID:objectID])];
845
+ }
846
+ }
847
+
848
+ @end