RATreeView.m 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. //The MIT License (MIT)
  2. //
  3. //Copyright (c) 2014 Rafał Augustyniak
  4. //
  5. //Permission is hereby granted, free of charge, to any person obtaining a copy of
  6. //this software and associated documentation files (the "Software"), to deal in
  7. //the Software without restriction, including without limitation the rights to
  8. //use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  9. //the Software, and to permit persons to whom the Software is furnished to do so,
  10. //subject to the following conditions:
  11. //
  12. //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  14. //FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  15. //COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  16. //IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  17. //CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  18. //
  19. #import "RATreeView.h"
  20. #import "RATreeView_ClassExtension.h"
  21. #import "RATreeView+Enums.h"
  22. #import "RATreeView+Private.h"
  23. #import "RABatchChanges.h"
  24. #import "RATreeNodeCollectionController.h"
  25. #import "RATreeNode.h"
  26. #import "RATableView.h"
  27. #pragma clang diagnostic push
  28. #pragma clang diagnostic ignored "-Wincomplete-implementation"
  29. @implementation RATreeView
  30. #pragma clang diagnostic pop
  31. #pragma mark Initializing a TreeView Object
  32. - (id)init
  33. {
  34. return [self initWithFrame:CGRectMake(0, 0, 100, 100) style:RATreeViewStylePlain];
  35. }
  36. - (id)initWithFrame:(CGRect)frame
  37. {
  38. return [self initWithFrame:frame style:RATreeViewStylePlain];
  39. }
  40. - (id)initWithFrame:(CGRect)frame style:(RATreeViewStyle)style
  41. {
  42. self = [super initWithFrame:frame];
  43. if (self) {
  44. CGRect innerFrame = CGRectMake(0, 0, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds));
  45. [self commonInitWithFrame:innerFrame style:style];
  46. }
  47. return self;
  48. }
  49. - (id)initWithCoder:(NSCoder *)aDecoder
  50. {
  51. self = [super initWithCoder:aDecoder];
  52. if (self) {
  53. CGRect innerFrame = CGRectMake(0, 0, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds));
  54. [self commonInitWithFrame:innerFrame style:RATreeViewStylePlain];
  55. }
  56. return self;
  57. }
  58. - (void)commonInitWithFrame:(CGRect)frame style:(RATreeViewStyle)style
  59. {
  60. UITableViewStyle tableViewStyle = [RATreeView tableViewStyleForTreeViewStyle:style];
  61. RATableView *tableView = [[RATableView alloc] initWithFrame:frame style:tableViewStyle];
  62. tableView.tableViewDelegate = (id<UITableViewDelegate>)self;
  63. tableView.dataSource = (id<UITableViewDataSource>)self;
  64. tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  65. tableView.backgroundColor = [UIColor clearColor];
  66. [self addSubview:tableView];
  67. [self setTableView:tableView];
  68. self.expandsChildRowsWhenRowExpands = NO;
  69. self.collapsesChildRowsWhenRowCollapses = NO;
  70. self.rowsExpandingAnimation = RATreeViewRowAnimationTop;
  71. self.rowsCollapsingAnimation = RATreeViewRowAnimationBottom;
  72. }
  73. - (void)awakeFromNib
  74. {
  75. [super awakeFromNib];
  76. self.tableView.backgroundColor = [UIColor clearColor];
  77. }
  78. #pragma mark Scroll View
  79. - (UIScrollView *)scrollView
  80. {
  81. return self.tableView;
  82. }
  83. #pragma mark Configuring a Tree View
  84. - (NSInteger)numberOfRows
  85. {
  86. return [self.tableView numberOfRowsInSection:0];
  87. }
  88. - (RATreeViewStyle)style
  89. {
  90. UITableViewStyle tableViewStyle = self.tableView.style;
  91. return [RATreeView treeViewStyleForTableViewStyle:tableViewStyle];
  92. }
  93. #if TARGET_OS_IOS
  94. - (RATreeViewCellSeparatorStyle)separatorStyle
  95. {
  96. RATreeViewCellSeparatorStyle style = [RATreeView treeViewCellSeparatorStyleForTableViewSeparatorStyle:self.tableView.separatorStyle];
  97. return style;
  98. }
  99. - (void)setSeparatorStyle:(RATreeViewCellSeparatorStyle)separatorStyle
  100. {
  101. UITableViewCellSeparatorStyle tableViewSeparatorStyle = [RATreeView tableViewCellSeparatorStyleForTreeViewCellSeparatorStyle:separatorStyle];
  102. self.tableView.separatorStyle = tableViewSeparatorStyle;
  103. }
  104. - (UIColor *)separatorColor
  105. {
  106. return self.tableView.separatorColor;
  107. }
  108. - (void)setSeparatorColor:(UIColor *)separatorColor
  109. {
  110. self.tableView.separatorColor = separatorColor;
  111. }
  112. #endif
  113. - (CGFloat)rowHeight
  114. {
  115. return self.tableView.rowHeight;
  116. }
  117. - (void)setRowHeight:(CGFloat)rowHeight
  118. {
  119. self.tableView.rowHeight = rowHeight;
  120. }
  121. - (CGFloat)estimatedRowHeight
  122. {
  123. if ([self.tableView respondsToSelector:@selector(estimatedRowHeight)]) {
  124. return self.tableView.estimatedRowHeight;
  125. } else {
  126. return 0;
  127. }
  128. }
  129. - (void)setEstimatedRowHeight:(CGFloat)estimatedRowHeight
  130. {
  131. if ([self.tableView respondsToSelector:@selector(estimatedRowHeight)]) {
  132. self.tableView.estimatedRowHeight = estimatedRowHeight;
  133. }
  134. }
  135. - (void)setEstimatedSectionHeaderHeight:(CGFloat)estimatedSectionHeaderHeight {
  136. if ([self.tableView respondsToSelector:@selector(estimatedSectionHeaderHeight)]) {
  137. self.tableView.estimatedSectionHeaderHeight = estimatedSectionHeaderHeight;
  138. }
  139. }
  140. - (void)setEstimatedSectionFooterHeight:(CGFloat)estimatedSectionFooterHeight {
  141. if ([self.tableView respondsToSelector:@selector(estimatedSectionFooterHeight)]) {
  142. self.tableView.estimatedSectionFooterHeight = estimatedSectionFooterHeight;
  143. }
  144. }
  145. - (UIEdgeInsets)separatorInset
  146. {
  147. if ([self.tableView respondsToSelector:@selector(separatorInset)]) {
  148. return self.tableView.separatorInset;
  149. } else {
  150. return UIEdgeInsetsZero;
  151. }
  152. }
  153. - (void)setSeparatorInset:(UIEdgeInsets)separatorInset
  154. {
  155. if ([self.tableView respondsToSelector:@selector(separatorInset)]) {
  156. self.tableView.separatorInset = separatorInset;
  157. }
  158. }
  159. #if TARGET_OS_IOS
  160. - (UIVisualEffect *)separatorEffect
  161. {
  162. if ([self.tableView respondsToSelector:@selector(separatorEffect)]) {
  163. return self.tableView.separatorEffect;
  164. } else {
  165. return nil;
  166. }
  167. }
  168. - (void)setSeparatorEffect:(UIVisualEffect *)separatorEffect
  169. {
  170. if ([self.tableView respondsToSelector:@selector(separatorEffect)]) {
  171. self.tableView.separatorEffect = separatorEffect;
  172. }
  173. }
  174. #endif
  175. - (BOOL)cellLayoutMarginsFollowReadableWidth
  176. {
  177. if ([self.tableView respondsToSelector:@selector(cellLayoutMarginsFollowReadableWidth)]) {
  178. return self.tableView.cellLayoutMarginsFollowReadableWidth;
  179. } else {
  180. return NO;
  181. }
  182. }
  183. - (void)setCellLayoutMarginsFollowReadableWidth:(BOOL)cellLayoutMarginsFollowReadableWidth
  184. {
  185. if ([self.tableView respondsToSelector:@selector(cellLayoutMarginsFollowReadableWidth)]) {
  186. self.tableView.cellLayoutMarginsFollowReadableWidth = cellLayoutMarginsFollowReadableWidth;
  187. }
  188. }
  189. - (UIView *)backgroundView
  190. {
  191. return self.tableView.backgroundView;
  192. }
  193. - (void)setBackgroundView:(UIView *)backgroundView
  194. {
  195. self.tableView.backgroundView = backgroundView;
  196. }
  197. #pragma mark Expanding and Collapsing Rows
  198. - (void)expandRowForItem:(id)item
  199. {
  200. [self expandRowForItem:item withRowAnimation:self.rowsExpandingAnimation];
  201. }
  202. - (void)expandRowForItem:(id)item withRowAnimation:(RATreeViewRowAnimation)animation
  203. {
  204. [self expandRowForItem:item expandChildren:NO withRowAnimation:animation];
  205. }
  206. - (void)expandRowForItem:(id)item expandChildren:(BOOL)expandChildren withRowAnimation:(RATreeViewRowAnimation)animation
  207. {
  208. NSIndexPath *indexPath = [self indexPathForItem:item];
  209. RATreeNode *treeNode = [self treeNodeForIndexPath:indexPath];
  210. if (!treeNode || treeNode.expanded) {
  211. return;
  212. }
  213. [self expandCellForTreeNode:treeNode expandChildren:expandChildren withRowAnimation:animation];
  214. }
  215. - (void)collapseRowForItem:(id)item
  216. {
  217. [self collapseRowForItem:item withRowAnimation:self.rowsCollapsingAnimation];
  218. }
  219. - (void)collapseRowForItem:(id)item withRowAnimation:(RATreeViewRowAnimation)animation
  220. {
  221. [self collapseRowForItem:item collapseChildren:NO withRowAnimation:animation];
  222. }
  223. - (void)collapseRowForItem:(id)item collapseChildren:(BOOL)collapseChildren withRowAnimation:(RATreeViewRowAnimation)animation
  224. {
  225. NSIndexPath *indexPath = [self indexPathForItem:item];
  226. RATreeNode *treeNode = [self treeNodeForIndexPath:indexPath];
  227. if (!treeNode) {
  228. return;
  229. }
  230. [self collapseCellForTreeNode:treeNode collapseChildren:collapseChildren withRowAnimation:animation];
  231. }
  232. #pragma mark - Changing tree's structure
  233. - (void)beginUpdates
  234. {
  235. [self.tableView beginUpdates];
  236. [self.batchChanges beginUpdates];
  237. }
  238. - (void)endUpdates
  239. {
  240. [self.batchChanges endUpdates];
  241. [self.tableView endUpdates];
  242. }
  243. - (void)insertItemsAtIndexes:(NSIndexSet *)indexes inParent:(id)parent withAnimation:(RATreeViewRowAnimation)animation
  244. {
  245. // if (parent && ![self isCellForItemExpanded:parent]) {
  246. // return;
  247. // }
  248. __weak __typeof(self) weakSelf = self;
  249. [indexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
  250. [weakSelf insertItemAtIndex:idx inParent:parent withAnimation:animation];
  251. }];
  252. }
  253. - (void)deleteItemsAtIndexes:(NSIndexSet *)indexes inParent:(id)parent withAnimation:(RATreeViewRowAnimation)animation
  254. {
  255. if (parent && ![self isCellForItemExpanded:parent]) {
  256. return;
  257. }
  258. __weak __typeof(self) weakSelf = self;
  259. [indexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
  260. [weakSelf removeItemAtIndex:idx inParent:parent withAnimation:animation];
  261. }];
  262. }
  263. #pragma mark - Creating Table View Cells
  264. - (void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier
  265. {
  266. [self.tableView registerNib:nib forCellReuseIdentifier:identifier];
  267. }
  268. - (void)registerClass:(Class)cellClass forCellReuseIdentifier:(NSString *)identifier
  269. {
  270. [self.tableView registerClass:cellClass forCellReuseIdentifier:identifier];
  271. }
  272. - (id)dequeueReusableCellWithIdentifier:(NSString *)identifier
  273. {
  274. return [self.tableView dequeueReusableCellWithIdentifier:identifier];
  275. }
  276. #pragma mark - Accessing Header and Footer Views
  277. - (void)registerNib:(UINib *)nib forHeaderFooterViewReuseIdentifier:(NSString *)identifier
  278. {
  279. [self.tableView registerNib:nib forHeaderFooterViewReuseIdentifier:identifier];
  280. }
  281. - (void)registerClass:(Class)aClass forHeaderFooterViewReuseIdentifier:(NSString *)identifier
  282. {
  283. [self.tableView registerClass:aClass forHeaderFooterViewReuseIdentifier:identifier];
  284. }
  285. - (id)dequeueReusableHeaderFooterViewWithIdentifier:(NSString *)identifier
  286. {
  287. return [self.tableView dequeueReusableHeaderFooterViewWithIdentifier:identifier];
  288. }
  289. - (UIView *)treeHeaderView
  290. {
  291. return self.tableView.tableHeaderView;
  292. }
  293. - (void)setTreeHeaderView:(UIView *)treeHeaderView
  294. {
  295. self.tableView.tableHeaderView = treeHeaderView;
  296. }
  297. - (UIView *)treeFooterView
  298. {
  299. return self.tableView.tableFooterView;
  300. }
  301. - (void)setTreeFooterView:(UIView *)treeFooterView
  302. {
  303. self.tableView.tableFooterView = treeFooterView;
  304. }
  305. #pragma mark - Working with Expandability
  306. - (BOOL)isCellForItemExpanded:(id)item
  307. {
  308. NSIndexPath *indexPath = [self indexPathForItem:item];
  309. return [self treeNodeForIndexPath:indexPath].expanded;
  310. }
  311. - (BOOL)isCellExpanded:(UITableViewCell *)cell
  312. {
  313. id item = [self itemForCell:cell];
  314. return [self isCellForItemExpanded:item];
  315. }
  316. #pragma mark - Working with Indentation
  317. - (NSInteger)levelForCellForItem:(id)item
  318. {
  319. return [self.treeNodeCollectionController levelForItem:item];
  320. }
  321. - (NSInteger)levelForCell:(UITableViewCell *)cell
  322. {
  323. id item = [self itemForCell:cell];
  324. return [self levelForCellForItem:item];
  325. }
  326. #pragma mark - Getting the Parent for an Item
  327. - (id)parentForItem:(id)item
  328. {
  329. return [self.treeNodeCollectionController parentForItem:item];
  330. }
  331. #pragma mark - Accessing Cells
  332. - (UITableViewCell *)cellForItem:(id)item
  333. {
  334. NSIndexPath *indexPath = [self indexPathForItem:item];
  335. return [self.tableView cellForRowAtIndexPath:indexPath];
  336. }
  337. - (NSArray *)visibleCells
  338. {
  339. return [self.tableView visibleCells];
  340. }
  341. - (id)itemForCell:(UITableViewCell *)cell
  342. {
  343. NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
  344. return [self treeNodeForIndexPath:indexPath].item;
  345. }
  346. - (id)itemForRowAtPoint:(CGPoint)point
  347. {
  348. NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:point];
  349. return !indexPath ? nil : [self treeNodeForIndexPath:indexPath].item;
  350. }
  351. - (id)itemsForRowsInRect:(CGRect)rect
  352. {
  353. NSArray *indexPaths = [self.tableView indexPathsForRowsInRect:rect];
  354. return [self itemsForIndexPaths:indexPaths];
  355. }
  356. - (NSArray *)itemsForVisibleRows
  357. {
  358. NSArray *indexPaths = [self.tableView indexPathsForVisibleRows];
  359. return [self itemsForIndexPaths:indexPaths];
  360. }
  361. #pragma mark - Scrolling the TreeView
  362. - (void)scrollToRowForItem:(id)item atScrollPosition:(RATreeViewScrollPosition)scrollPosition animated:(BOOL)animated
  363. {
  364. NSIndexPath *indexPath = [self indexPathForItem:item];
  365. UITableViewScrollPosition tableViewScrollPosition = [RATreeView tableViewScrollPositionForTreeViewScrollPosition:scrollPosition];
  366. [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:tableViewScrollPosition animated:animated];
  367. }
  368. - (void)scrollToNearestSelectedRowAtScrollPosition:(RATreeViewScrollPosition)scrollPosition animated:(BOOL)animated
  369. {
  370. UITableViewScrollPosition tableViewScrollPosition = [RATreeView tableViewScrollPositionForTreeViewScrollPosition:scrollPosition];
  371. [self.tableView scrollToNearestSelectedRowAtScrollPosition:tableViewScrollPosition animated:animated];
  372. }
  373. #pragma mark - Managing Selections
  374. - (id)itemForSelectedRow
  375. {
  376. NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
  377. return [self treeNodeForIndexPath:indexPath].item;
  378. }
  379. - (NSArray *)itemsForSelectedRows
  380. {
  381. NSArray *selectedRows = [self.tableView indexPathsForSelectedRows];
  382. return [self itemsForIndexPaths:selectedRows];
  383. }
  384. - (void)selectRowForItem:(id)item animated:(BOOL)animated scrollPosition:(RATreeViewScrollPosition)scrollPosition
  385. {
  386. if ([self isCellForItemExpanded:[self parentForItem:item]]) {
  387. NSIndexPath *indexPath = [self indexPathForItem:item];
  388. UITableViewScrollPosition tableViewScrollPosition = [RATreeView tableViewScrollPositionForTreeViewScrollPosition:scrollPosition];
  389. [self.tableView selectRowAtIndexPath:indexPath animated:animated scrollPosition:tableViewScrollPosition];
  390. }
  391. }
  392. - (void)deselectRowForItem:(id)item animated:(BOOL)animated
  393. {
  394. if ([self isCellForItemExpanded:[self parentForItem:item]]) {
  395. NSIndexPath *indexPath = [self indexPathForItem:item];
  396. [self.tableView deselectRowAtIndexPath:indexPath animated:animated];
  397. }
  398. }
  399. - (BOOL)allowsSelection
  400. {
  401. return self.tableView.allowsSelection;
  402. }
  403. - (void)setAllowsSelection:(BOOL)allowsSelection
  404. {
  405. self.tableView.allowsSelection = allowsSelection;
  406. }
  407. - (BOOL)allowsMultipleSelection
  408. {
  409. return self.tableView.allowsMultipleSelection;
  410. }
  411. - (void)setAllowsMultipleSelection:(BOOL)allowsMultipleSelection
  412. {
  413. self.tableView.allowsMultipleSelection = allowsMultipleSelection;
  414. }
  415. - (BOOL)allowsSelectionDuringEditing
  416. {
  417. return self.tableView.allowsSelectionDuringEditing;
  418. }
  419. - (void)setAllowsSelectionDuringEditing:(BOOL)allowsSelectionDuringEditing
  420. {
  421. self.tableView.allowsSelectionDuringEditing = allowsSelectionDuringEditing;
  422. }
  423. - (BOOL)allowsMultipleSelectionDuringEditing
  424. {
  425. return self.tableView.allowsMultipleSelectionDuringEditing;
  426. }
  427. - (void)setAllowsMultipleSelectionDuringEditing:(BOOL)allowsMultipleSelectionDuringEditing
  428. {
  429. self.tableView.allowsMultipleSelectionDuringEditing = allowsMultipleSelectionDuringEditing;
  430. }
  431. #pragma mark - Managing the Editing of Tree Cells
  432. - (BOOL)isEditing
  433. {
  434. return self.tableView.isEditing;
  435. }
  436. - (void)setEditing:(BOOL)editing
  437. {
  438. self.tableView.editing = editing;
  439. }
  440. - (void)setEditing:(BOOL)editing animated:(BOOL)animated
  441. {
  442. [self.tableView setEditing:editing animated:animated];
  443. }
  444. #pragma mark - Reloading the Tree View
  445. - (void)reloadData
  446. {
  447. [self setupTreeStructure];
  448. [self.tableView reloadData];
  449. }
  450. - (void)reloadRowsForItems:(NSArray *)items withRowAnimation:(RATreeViewRowAnimation)animation
  451. {
  452. NSMutableArray *indexes = [NSMutableArray array];
  453. UITableViewRowAnimation tableViewRowAnimation = [RATreeView tableViewRowAnimationForTreeViewRowAnimation:animation];
  454. for (id item in items) {
  455. NSIndexPath *indexPath = [self indexPathForItem:item];
  456. [indexes addObject:indexPath];
  457. }
  458. [self.tableView reloadRowsAtIndexPaths:indexes withRowAnimation:tableViewRowAnimation];
  459. }
  460. - (void)reloadRows
  461. {
  462. NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:0];
  463. [self.tableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationNone];
  464. }
  465. #pragma mark - UIScrollView's properties
  466. - (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated
  467. {
  468. [self.tableView setContentOffset:contentOffset animated:animated];
  469. }
  470. - (void)scrollRectToVisible:(CGRect)visible animated:(BOOL)animated
  471. {
  472. [self.tableView scrollRectToVisible:visible animated:animated];
  473. }
  474. - (void)setZoomScale:(CGFloat)zoomScale animated:(BOOL)animated
  475. {
  476. [self.tableView setZoomScale:zoomScale animated:animated];
  477. }
  478. - (void)flashScrollIndicators
  479. {
  480. [self.tableView flashScrollIndicators];
  481. }
  482. - (void)zoomToRect:(CGRect)rect animated:(BOOL)animated
  483. {
  484. [self.tableView zoomToRect:rect animated:animated];
  485. }
  486. #pragma mark -
  487. - (NSArray *)itemsForIndexPaths:(NSArray *)indexPaths
  488. {
  489. if (!indexPaths) {
  490. return nil;
  491. }
  492. NSMutableArray *items = [NSMutableArray array];
  493. for (NSIndexPath *indexPath in indexPaths) {
  494. [items addObject:[self treeNodeForIndexPath:indexPath].item];
  495. }
  496. return [items copy];
  497. }
  498. @end