├── README.md
├── ZFVoteViewDemo.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ └── xcuserdata
│ │ └── dzmacbook.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
└── xcuserdata
│ ├── dzmacbook.xcuserdatad
│ └── xcschemes
│ │ └── xcschememanagement.plist
│ └── saitechuanmeigufenyouxiangongsi.xcuserdatad
│ └── xcschemes
│ ├── ZFVoteViewDemo.xcscheme
│ └── xcschememanagement.plist
├── ZFVoteViewDemo
├── AppDelegate.h
├── AppDelegate.m
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── AppIcon29x29@2x.png
│ │ ├── AppIcon29x29@3x.png
│ │ ├── AppIcon40x40@2x.png
│ │ ├── AppIcon40x40@3x.png
│ │ ├── AppIcon60x60@2x.png
│ │ ├── AppIcon60x60@3x.png
│ │ └── Contents.json
│ ├── Contents.json
│ ├── Like-Blue.imageset
│ │ ├── Contents.json
│ │ └── Like-Blue.png
│ └── Like-PlaceHold.imageset
│ │ ├── Contents.json
│ │ └── Like-PlaceHold.png
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── Info.plist
├── MJExtension
│ ├── MJExtension.h
│ ├── MJExtensionConst.h
│ ├── MJExtensionConst.m
│ ├── MJFoundation.h
│ ├── MJFoundation.m
│ ├── MJProperty.h
│ ├── MJProperty.m
│ ├── MJPropertyKey.h
│ ├── MJPropertyKey.m
│ ├── MJPropertyType.h
│ ├── MJPropertyType.m
│ ├── NSObject+MJClass.h
│ ├── NSObject+MJClass.m
│ ├── NSObject+MJCoding.h
│ ├── NSObject+MJCoding.m
│ ├── NSObject+MJKeyValue.h
│ ├── NSObject+MJKeyValue.m
│ ├── NSObject+MJProperty.h
│ ├── NSObject+MJProperty.m
│ ├── NSString+MJExtension.h
│ └── NSString+MJExtension.m
├── UIView+Extension.h
├── UIView+Extension.m
├── ViewController.h
├── ViewController.m
├── ZFConfig.h
├── ZFPercentBar.h
├── ZFPercentBar.m
├── ZFVoteCell.h
├── ZFVoteCell.m
├── ZFVoteModel.h
├── ZFVoteModel.m
├── ZFVoteTableView.h
├── ZFVoteTableView.m
├── ZFVoteView.h
├── ZFVoteView.m
└── main.m
├── ZFVoteViewDemoTests
├── Info.plist
└── ZFVoteViewDemoTests.m
├── ZFVoteViewDemoUITests
├── Info.plist
└── ZFVoteViewDemoUITests.m
├── abc.plist
├── 格瓦拉投票效果1.gif
├── 格瓦拉投票效果2.gif
└── 格瓦拉投票效果3.gif
/README.md:
--------------------------------------------------------------------------------
1 | # ZFVoteViewDemo(觉得好麻烦给个星star)
2 |
3 | github地址:https://github.com/ZFbaby/ZFVoteViewDemo
4 |
5 | ##tabelView实现格瓦拉飞天投票效果
6 |
7 | 感谢GraphKit作者,demo中的绘图功能大部分实现采用他的方法和思路做的并进行了一些小改!
8 |
9 | 格瓦拉目前来说动画效果确实做的还比较好,虽然不是说很炫但做到精致,这次就模仿了它投票的模块
10 |
11 | 其实想到要实现它的方法很多,这次我就采用了苹果自带功能强大的控件UITableView
12 |
13 | ####ZFVoteViewDemo功能介绍
14 |
15 | 1. 点击投票后当前控件实现飞天效果并转移到最顶部
16 | 2. 当控件放大时cell上文字实现自适应宽高
17 | 3. 按钮实现弹性放大效果,进度条动画比例等效果
18 |
19 |
20 | **效果图如下**
21 |
22 | 
23 | 
24 | 
25 |
26 | ######实现步骤:
27 | * 数据回来的时候就要根据数据算出每一行的高度并且算出总高
28 | * 设置cell的内边距离及x值
29 | * 创建投票主控件并添加到cell上
30 | * 每次点击选择一个cell的时候创建个投票主控件实现动画效果
31 | * 再用tableview的交换cell位置的方法实现cell的转换
32 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 366DC1C31D65544700691A3B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 366DC1C21D65544700691A3B /* main.m */; };
11 | 366DC1C61D65544700691A3B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 366DC1C51D65544700691A3B /* AppDelegate.m */; };
12 | 366DC1C91D65544700691A3B /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 366DC1C81D65544700691A3B /* ViewController.m */; };
13 | 366DC1CC1D65544700691A3B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 366DC1CA1D65544700691A3B /* Main.storyboard */; };
14 | 366DC1CE1D65544700691A3B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 366DC1CD1D65544700691A3B /* Assets.xcassets */; };
15 | 366DC1D11D65544700691A3B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 366DC1CF1D65544700691A3B /* LaunchScreen.storyboard */; };
16 | 366DC1DC1D65544700691A3B /* ZFVoteViewDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 366DC1DB1D65544700691A3B /* ZFVoteViewDemoTests.m */; };
17 | 366DC1E71D65544700691A3B /* ZFVoteViewDemoUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 366DC1E61D65544700691A3B /* ZFVoteViewDemoUITests.m */; };
18 | 366DC1F51D6563DF00691A3B /* abc.plist in Resources */ = {isa = PBXBuildFile; fileRef = 366DC1F41D6563DF00691A3B /* abc.plist */; };
19 | 366DC21C1D6581AB00691A3B /* ZFVoteModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 366DC21B1D6581AB00691A3B /* ZFVoteModel.m */; };
20 | 366DC2201D65856A00691A3B /* ZFVoteCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 366DC21F1D65856A00691A3B /* ZFVoteCell.m */; };
21 | 366DC2231D6587AC00691A3B /* UIView+Extension.m in Sources */ = {isa = PBXBuildFile; fileRef = 366DC2221D6587AC00691A3B /* UIView+Extension.m */; };
22 | 366DC2551D66D43100691A3B /* ZFVoteView.m in Sources */ = {isa = PBXBuildFile; fileRef = 366DC2541D66D43100691A3B /* ZFVoteView.m */; };
23 | 366DC2581D67509600691A3B /* ZFPercentBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 366DC2571D67509600691A3B /* ZFPercentBar.m */; };
24 | 366DC25B1D6A91FB00691A3B /* ZFVoteTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 366DC25A1D6A91FB00691A3B /* ZFVoteTableView.m */; };
25 | 366DC2621D6AF65000691A3B /* 格瓦拉投票效果1.gif in Resources */ = {isa = PBXBuildFile; fileRef = 366DC25F1D6AF65000691A3B /* 格瓦拉投票效果1.gif */; };
26 | 366DC2641D6AF65000691A3B /* 格瓦拉投票效果2.gif in Resources */ = {isa = PBXBuildFile; fileRef = 366DC2611D6AF65000691A3B /* 格瓦拉投票效果2.gif */; };
27 | 366DC2691D6AFCAE00691A3B /* README.md in Sources */ = {isa = PBXBuildFile; fileRef = 366DC2681D6AFCAE00691A3B /* README.md */; };
28 | 366DC26B1D6B2CC800691A3B /* 格瓦拉投票效果3.gif in Resources */ = {isa = PBXBuildFile; fileRef = 366DC26A1D6B2CC800691A3B /* 格瓦拉投票效果3.gif */; };
29 | 36B6EEEE1D6C1518005C3FBF /* MJExtensionConst.m in Sources */ = {isa = PBXBuildFile; fileRef = 36B6EEDA1D6C1518005C3FBF /* MJExtensionConst.m */; };
30 | 36B6EEEF1D6C1518005C3FBF /* MJFoundation.m in Sources */ = {isa = PBXBuildFile; fileRef = 36B6EEDC1D6C1518005C3FBF /* MJFoundation.m */; };
31 | 36B6EEF01D6C1518005C3FBF /* MJProperty.m in Sources */ = {isa = PBXBuildFile; fileRef = 36B6EEDE1D6C1518005C3FBF /* MJProperty.m */; };
32 | 36B6EEF11D6C1518005C3FBF /* MJPropertyKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 36B6EEE01D6C1518005C3FBF /* MJPropertyKey.m */; };
33 | 36B6EEF21D6C1518005C3FBF /* MJPropertyType.m in Sources */ = {isa = PBXBuildFile; fileRef = 36B6EEE21D6C1518005C3FBF /* MJPropertyType.m */; };
34 | 36B6EEF31D6C1518005C3FBF /* NSObject+MJClass.m in Sources */ = {isa = PBXBuildFile; fileRef = 36B6EEE41D6C1518005C3FBF /* NSObject+MJClass.m */; };
35 | 36B6EEF41D6C1518005C3FBF /* NSObject+MJCoding.m in Sources */ = {isa = PBXBuildFile; fileRef = 36B6EEE61D6C1518005C3FBF /* NSObject+MJCoding.m */; };
36 | 36B6EEF51D6C1518005C3FBF /* NSObject+MJKeyValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 36B6EEE81D6C1518005C3FBF /* NSObject+MJKeyValue.m */; };
37 | 36B6EEF61D6C1518005C3FBF /* NSObject+MJProperty.m in Sources */ = {isa = PBXBuildFile; fileRef = 36B6EEEA1D6C1518005C3FBF /* NSObject+MJProperty.m */; };
38 | 36B6EEF71D6C1518005C3FBF /* NSString+MJExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 36B6EEEC1D6C1518005C3FBF /* NSString+MJExtension.m */; };
39 | /* End PBXBuildFile section */
40 |
41 | /* Begin PBXContainerItemProxy section */
42 | 366DC1D81D65544700691A3B /* PBXContainerItemProxy */ = {
43 | isa = PBXContainerItemProxy;
44 | containerPortal = 366DC1B61D65544700691A3B /* Project object */;
45 | proxyType = 1;
46 | remoteGlobalIDString = 366DC1BD1D65544700691A3B;
47 | remoteInfo = ZFVoteViewDemo;
48 | };
49 | 366DC1E31D65544700691A3B /* PBXContainerItemProxy */ = {
50 | isa = PBXContainerItemProxy;
51 | containerPortal = 366DC1B61D65544700691A3B /* Project object */;
52 | proxyType = 1;
53 | remoteGlobalIDString = 366DC1BD1D65544700691A3B;
54 | remoteInfo = ZFVoteViewDemo;
55 | };
56 | /* End PBXContainerItemProxy section */
57 |
58 | /* Begin PBXFileReference section */
59 | 366DC1BE1D65544700691A3B /* ZFVoteViewDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ZFVoteViewDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
60 | 366DC1C21D65544700691A3B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
61 | 366DC1C41D65544700691A3B /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
62 | 366DC1C51D65544700691A3B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
63 | 366DC1C71D65544700691A3B /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; };
64 | 366DC1C81D65544700691A3B /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; };
65 | 366DC1CB1D65544700691A3B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
66 | 366DC1CD1D65544700691A3B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
67 | 366DC1D01D65544700691A3B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
68 | 366DC1D21D65544700691A3B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
69 | 366DC1D71D65544700691A3B /* ZFVoteViewDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ZFVoteViewDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
70 | 366DC1DB1D65544700691A3B /* ZFVoteViewDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ZFVoteViewDemoTests.m; sourceTree = ""; };
71 | 366DC1DD1D65544700691A3B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
72 | 366DC1E21D65544700691A3B /* ZFVoteViewDemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ZFVoteViewDemoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
73 | 366DC1E61D65544700691A3B /* ZFVoteViewDemoUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ZFVoteViewDemoUITests.m; sourceTree = ""; };
74 | 366DC1E81D65544700691A3B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
75 | 366DC1F41D6563DF00691A3B /* abc.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = abc.plist; sourceTree = ""; };
76 | 366DC21A1D6581AB00691A3B /* ZFVoteModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFVoteModel.h; sourceTree = ""; };
77 | 366DC21B1D6581AB00691A3B /* ZFVoteModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFVoteModel.m; sourceTree = ""; };
78 | 366DC21E1D65856A00691A3B /* ZFVoteCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFVoteCell.h; sourceTree = ""; };
79 | 366DC21F1D65856A00691A3B /* ZFVoteCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFVoteCell.m; sourceTree = ""; };
80 | 366DC2211D6587AC00691A3B /* UIView+Extension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Extension.h"; sourceTree = ""; };
81 | 366DC2221D6587AC00691A3B /* UIView+Extension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Extension.m"; sourceTree = ""; };
82 | 366DC24A1D659ED900691A3B /* ZFConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFConfig.h; sourceTree = ""; };
83 | 366DC2531D66D43100691A3B /* ZFVoteView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFVoteView.h; sourceTree = ""; };
84 | 366DC2541D66D43100691A3B /* ZFVoteView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFVoteView.m; sourceTree = ""; };
85 | 366DC2561D67509600691A3B /* ZFPercentBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFPercentBar.h; sourceTree = ""; };
86 | 366DC2571D67509600691A3B /* ZFPercentBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFPercentBar.m; sourceTree = ""; };
87 | 366DC2591D6A91FB00691A3B /* ZFVoteTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFVoteTableView.h; sourceTree = ""; };
88 | 366DC25A1D6A91FB00691A3B /* ZFVoteTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFVoteTableView.m; sourceTree = ""; };
89 | 366DC25F1D6AF65000691A3B /* 格瓦拉投票效果1.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = "格瓦拉投票效果1.gif"; sourceTree = ""; };
90 | 366DC2611D6AF65000691A3B /* 格瓦拉投票效果2.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = "格瓦拉投票效果2.gif"; sourceTree = ""; };
91 | 366DC2681D6AFCAE00691A3B /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
92 | 366DC26A1D6B2CC800691A3B /* 格瓦拉投票效果3.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = "格瓦拉投票效果3.gif"; sourceTree = ""; };
93 | 36B6EED81D6C1518005C3FBF /* MJExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MJExtension.h; sourceTree = ""; };
94 | 36B6EED91D6C1518005C3FBF /* MJExtensionConst.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MJExtensionConst.h; sourceTree = ""; };
95 | 36B6EEDA1D6C1518005C3FBF /* MJExtensionConst.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MJExtensionConst.m; sourceTree = ""; };
96 | 36B6EEDB1D6C1518005C3FBF /* MJFoundation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MJFoundation.h; sourceTree = ""; };
97 | 36B6EEDC1D6C1518005C3FBF /* MJFoundation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MJFoundation.m; sourceTree = ""; };
98 | 36B6EEDD1D6C1518005C3FBF /* MJProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MJProperty.h; sourceTree = ""; };
99 | 36B6EEDE1D6C1518005C3FBF /* MJProperty.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MJProperty.m; sourceTree = ""; };
100 | 36B6EEDF1D6C1518005C3FBF /* MJPropertyKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MJPropertyKey.h; sourceTree = ""; };
101 | 36B6EEE01D6C1518005C3FBF /* MJPropertyKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MJPropertyKey.m; sourceTree = ""; };
102 | 36B6EEE11D6C1518005C3FBF /* MJPropertyType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MJPropertyType.h; sourceTree = ""; };
103 | 36B6EEE21D6C1518005C3FBF /* MJPropertyType.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MJPropertyType.m; sourceTree = ""; };
104 | 36B6EEE31D6C1518005C3FBF /* NSObject+MJClass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+MJClass.h"; sourceTree = ""; };
105 | 36B6EEE41D6C1518005C3FBF /* NSObject+MJClass.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+MJClass.m"; sourceTree = ""; };
106 | 36B6EEE51D6C1518005C3FBF /* NSObject+MJCoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+MJCoding.h"; sourceTree = ""; };
107 | 36B6EEE61D6C1518005C3FBF /* NSObject+MJCoding.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+MJCoding.m"; sourceTree = ""; };
108 | 36B6EEE71D6C1518005C3FBF /* NSObject+MJKeyValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+MJKeyValue.h"; sourceTree = ""; };
109 | 36B6EEE81D6C1518005C3FBF /* NSObject+MJKeyValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+MJKeyValue.m"; sourceTree = ""; };
110 | 36B6EEE91D6C1518005C3FBF /* NSObject+MJProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+MJProperty.h"; sourceTree = ""; };
111 | 36B6EEEA1D6C1518005C3FBF /* NSObject+MJProperty.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+MJProperty.m"; sourceTree = ""; };
112 | 36B6EEEB1D6C1518005C3FBF /* NSString+MJExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+MJExtension.h"; sourceTree = ""; };
113 | 36B6EEEC1D6C1518005C3FBF /* NSString+MJExtension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+MJExtension.m"; sourceTree = ""; };
114 | /* End PBXFileReference section */
115 |
116 | /* Begin PBXFrameworksBuildPhase section */
117 | 366DC1BB1D65544700691A3B /* Frameworks */ = {
118 | isa = PBXFrameworksBuildPhase;
119 | buildActionMask = 2147483647;
120 | files = (
121 | );
122 | runOnlyForDeploymentPostprocessing = 0;
123 | };
124 | 366DC1D41D65544700691A3B /* Frameworks */ = {
125 | isa = PBXFrameworksBuildPhase;
126 | buildActionMask = 2147483647;
127 | files = (
128 | );
129 | runOnlyForDeploymentPostprocessing = 0;
130 | };
131 | 366DC1DF1D65544700691A3B /* Frameworks */ = {
132 | isa = PBXFrameworksBuildPhase;
133 | buildActionMask = 2147483647;
134 | files = (
135 | );
136 | runOnlyForDeploymentPostprocessing = 0;
137 | };
138 | /* End PBXFrameworksBuildPhase section */
139 |
140 | /* Begin PBXGroup section */
141 | 366DC1B51D65544700691A3B = {
142 | isa = PBXGroup;
143 | children = (
144 | 366DC25F1D6AF65000691A3B /* 格瓦拉投票效果1.gif */,
145 | 366DC2611D6AF65000691A3B /* 格瓦拉投票效果2.gif */,
146 | 366DC26A1D6B2CC800691A3B /* 格瓦拉投票效果3.gif */,
147 | 366DC1F41D6563DF00691A3B /* abc.plist */,
148 | 366DC2681D6AFCAE00691A3B /* README.md */,
149 | 366DC1C01D65544700691A3B /* ZFVoteViewDemo */,
150 | 366DC1DA1D65544700691A3B /* ZFVoteViewDemoTests */,
151 | 366DC1E51D65544700691A3B /* ZFVoteViewDemoUITests */,
152 | 366DC1BF1D65544700691A3B /* Products */,
153 | );
154 | sourceTree = "";
155 | };
156 | 366DC1BF1D65544700691A3B /* Products */ = {
157 | isa = PBXGroup;
158 | children = (
159 | 366DC1BE1D65544700691A3B /* ZFVoteViewDemo.app */,
160 | 366DC1D71D65544700691A3B /* ZFVoteViewDemoTests.xctest */,
161 | 366DC1E21D65544700691A3B /* ZFVoteViewDemoUITests.xctest */,
162 | );
163 | name = Products;
164 | sourceTree = "";
165 | };
166 | 366DC1C01D65544700691A3B /* ZFVoteViewDemo */ = {
167 | isa = PBXGroup;
168 | children = (
169 | 366DC2651D6AF6B300691A3B /* Controller */,
170 | 366DC21D1D65832600691A3B /* View */,
171 | 366DC2191D65817600691A3B /* Model */,
172 | 366DC1F61D65815600691A3B /* Lib */,
173 | 366DC1CD1D65544700691A3B /* Assets.xcassets */,
174 | 366DC1CF1D65544700691A3B /* LaunchScreen.storyboard */,
175 | 366DC1D21D65544700691A3B /* Info.plist */,
176 | 366DC1C11D65544700691A3B /* Supporting Files */,
177 | );
178 | path = ZFVoteViewDemo;
179 | sourceTree = "";
180 | };
181 | 366DC1C11D65544700691A3B /* Supporting Files */ = {
182 | isa = PBXGroup;
183 | children = (
184 | 366DC1C21D65544700691A3B /* main.m */,
185 | );
186 | name = "Supporting Files";
187 | sourceTree = "";
188 | };
189 | 366DC1DA1D65544700691A3B /* ZFVoteViewDemoTests */ = {
190 | isa = PBXGroup;
191 | children = (
192 | 366DC1DB1D65544700691A3B /* ZFVoteViewDemoTests.m */,
193 | 366DC1DD1D65544700691A3B /* Info.plist */,
194 | );
195 | path = ZFVoteViewDemoTests;
196 | sourceTree = "";
197 | };
198 | 366DC1E51D65544700691A3B /* ZFVoteViewDemoUITests */ = {
199 | isa = PBXGroup;
200 | children = (
201 | 366DC1E61D65544700691A3B /* ZFVoteViewDemoUITests.m */,
202 | 366DC1E81D65544700691A3B /* Info.plist */,
203 | );
204 | path = ZFVoteViewDemoUITests;
205 | sourceTree = "";
206 | };
207 | 366DC1F61D65815600691A3B /* Lib */ = {
208 | isa = PBXGroup;
209 | children = (
210 | 36B6EED61D6C1518005C3FBF /* MJExtension */,
211 | );
212 | name = Lib;
213 | sourceTree = "";
214 | };
215 | 366DC2191D65817600691A3B /* Model */ = {
216 | isa = PBXGroup;
217 | children = (
218 | 366DC21A1D6581AB00691A3B /* ZFVoteModel.h */,
219 | 366DC21B1D6581AB00691A3B /* ZFVoteModel.m */,
220 | );
221 | name = Model;
222 | sourceTree = "";
223 | };
224 | 366DC21D1D65832600691A3B /* View */ = {
225 | isa = PBXGroup;
226 | children = (
227 | 366DC2561D67509600691A3B /* ZFPercentBar.h */,
228 | 366DC2571D67509600691A3B /* ZFPercentBar.m */,
229 | 366DC2211D6587AC00691A3B /* UIView+Extension.h */,
230 | 366DC2221D6587AC00691A3B /* UIView+Extension.m */,
231 | 366DC21E1D65856A00691A3B /* ZFVoteCell.h */,
232 | 366DC21F1D65856A00691A3B /* ZFVoteCell.m */,
233 | 366DC24A1D659ED900691A3B /* ZFConfig.h */,
234 | 366DC2531D66D43100691A3B /* ZFVoteView.h */,
235 | 366DC2541D66D43100691A3B /* ZFVoteView.m */,
236 | 366DC2591D6A91FB00691A3B /* ZFVoteTableView.h */,
237 | 366DC25A1D6A91FB00691A3B /* ZFVoteTableView.m */,
238 | );
239 | name = View;
240 | sourceTree = "";
241 | };
242 | 366DC2651D6AF6B300691A3B /* Controller */ = {
243 | isa = PBXGroup;
244 | children = (
245 | 366DC1C41D65544700691A3B /* AppDelegate.h */,
246 | 366DC1C51D65544700691A3B /* AppDelegate.m */,
247 | 366DC1C71D65544700691A3B /* ViewController.h */,
248 | 366DC1C81D65544700691A3B /* ViewController.m */,
249 | 366DC1CA1D65544700691A3B /* Main.storyboard */,
250 | );
251 | name = Controller;
252 | sourceTree = "";
253 | };
254 | 36B6EED61D6C1518005C3FBF /* MJExtension */ = {
255 | isa = PBXGroup;
256 | children = (
257 | 36B6EED81D6C1518005C3FBF /* MJExtension.h */,
258 | 36B6EED91D6C1518005C3FBF /* MJExtensionConst.h */,
259 | 36B6EEDA1D6C1518005C3FBF /* MJExtensionConst.m */,
260 | 36B6EEDB1D6C1518005C3FBF /* MJFoundation.h */,
261 | 36B6EEDC1D6C1518005C3FBF /* MJFoundation.m */,
262 | 36B6EEDD1D6C1518005C3FBF /* MJProperty.h */,
263 | 36B6EEDE1D6C1518005C3FBF /* MJProperty.m */,
264 | 36B6EEDF1D6C1518005C3FBF /* MJPropertyKey.h */,
265 | 36B6EEE01D6C1518005C3FBF /* MJPropertyKey.m */,
266 | 36B6EEE11D6C1518005C3FBF /* MJPropertyType.h */,
267 | 36B6EEE21D6C1518005C3FBF /* MJPropertyType.m */,
268 | 36B6EEE31D6C1518005C3FBF /* NSObject+MJClass.h */,
269 | 36B6EEE41D6C1518005C3FBF /* NSObject+MJClass.m */,
270 | 36B6EEE51D6C1518005C3FBF /* NSObject+MJCoding.h */,
271 | 36B6EEE61D6C1518005C3FBF /* NSObject+MJCoding.m */,
272 | 36B6EEE71D6C1518005C3FBF /* NSObject+MJKeyValue.h */,
273 | 36B6EEE81D6C1518005C3FBF /* NSObject+MJKeyValue.m */,
274 | 36B6EEE91D6C1518005C3FBF /* NSObject+MJProperty.h */,
275 | 36B6EEEA1D6C1518005C3FBF /* NSObject+MJProperty.m */,
276 | 36B6EEEB1D6C1518005C3FBF /* NSString+MJExtension.h */,
277 | 36B6EEEC1D6C1518005C3FBF /* NSString+MJExtension.m */,
278 | );
279 | path = MJExtension;
280 | sourceTree = "";
281 | };
282 | /* End PBXGroup section */
283 |
284 | /* Begin PBXNativeTarget section */
285 | 366DC1BD1D65544700691A3B /* ZFVoteViewDemo */ = {
286 | isa = PBXNativeTarget;
287 | buildConfigurationList = 366DC1EB1D65544700691A3B /* Build configuration list for PBXNativeTarget "ZFVoteViewDemo" */;
288 | buildPhases = (
289 | 366DC1BA1D65544700691A3B /* Sources */,
290 | 366DC1BB1D65544700691A3B /* Frameworks */,
291 | 366DC1BC1D65544700691A3B /* Resources */,
292 | );
293 | buildRules = (
294 | );
295 | dependencies = (
296 | );
297 | name = ZFVoteViewDemo;
298 | productName = ZFVoteViewDemo;
299 | productReference = 366DC1BE1D65544700691A3B /* ZFVoteViewDemo.app */;
300 | productType = "com.apple.product-type.application";
301 | };
302 | 366DC1D61D65544700691A3B /* ZFVoteViewDemoTests */ = {
303 | isa = PBXNativeTarget;
304 | buildConfigurationList = 366DC1EE1D65544700691A3B /* Build configuration list for PBXNativeTarget "ZFVoteViewDemoTests" */;
305 | buildPhases = (
306 | 366DC1D31D65544700691A3B /* Sources */,
307 | 366DC1D41D65544700691A3B /* Frameworks */,
308 | 366DC1D51D65544700691A3B /* Resources */,
309 | );
310 | buildRules = (
311 | );
312 | dependencies = (
313 | 366DC1D91D65544700691A3B /* PBXTargetDependency */,
314 | );
315 | name = ZFVoteViewDemoTests;
316 | productName = ZFVoteViewDemoTests;
317 | productReference = 366DC1D71D65544700691A3B /* ZFVoteViewDemoTests.xctest */;
318 | productType = "com.apple.product-type.bundle.unit-test";
319 | };
320 | 366DC1E11D65544700691A3B /* ZFVoteViewDemoUITests */ = {
321 | isa = PBXNativeTarget;
322 | buildConfigurationList = 366DC1F11D65544700691A3B /* Build configuration list for PBXNativeTarget "ZFVoteViewDemoUITests" */;
323 | buildPhases = (
324 | 366DC1DE1D65544700691A3B /* Sources */,
325 | 366DC1DF1D65544700691A3B /* Frameworks */,
326 | 366DC1E01D65544700691A3B /* Resources */,
327 | );
328 | buildRules = (
329 | );
330 | dependencies = (
331 | 366DC1E41D65544700691A3B /* PBXTargetDependency */,
332 | );
333 | name = ZFVoteViewDemoUITests;
334 | productName = ZFVoteViewDemoUITests;
335 | productReference = 366DC1E21D65544700691A3B /* ZFVoteViewDemoUITests.xctest */;
336 | productType = "com.apple.product-type.bundle.ui-testing";
337 | };
338 | /* End PBXNativeTarget section */
339 |
340 | /* Begin PBXProject section */
341 | 366DC1B61D65544700691A3B /* Project object */ = {
342 | isa = PBXProject;
343 | attributes = {
344 | LastUpgradeCheck = 0730;
345 | ORGANIZATIONNAME = ZFbory;
346 | TargetAttributes = {
347 | 366DC1BD1D65544700691A3B = {
348 | CreatedOnToolsVersion = 7.3;
349 | };
350 | 366DC1D61D65544700691A3B = {
351 | CreatedOnToolsVersion = 7.3;
352 | TestTargetID = 366DC1BD1D65544700691A3B;
353 | };
354 | 366DC1E11D65544700691A3B = {
355 | CreatedOnToolsVersion = 7.3;
356 | TestTargetID = 366DC1BD1D65544700691A3B;
357 | };
358 | };
359 | };
360 | buildConfigurationList = 366DC1B91D65544700691A3B /* Build configuration list for PBXProject "ZFVoteViewDemo" */;
361 | compatibilityVersion = "Xcode 3.2";
362 | developmentRegion = English;
363 | hasScannedForEncodings = 0;
364 | knownRegions = (
365 | English,
366 | en,
367 | Base,
368 | );
369 | mainGroup = 366DC1B51D65544700691A3B;
370 | productRefGroup = 366DC1BF1D65544700691A3B /* Products */;
371 | projectDirPath = "";
372 | projectRoot = "";
373 | targets = (
374 | 366DC1BD1D65544700691A3B /* ZFVoteViewDemo */,
375 | 366DC1D61D65544700691A3B /* ZFVoteViewDemoTests */,
376 | 366DC1E11D65544700691A3B /* ZFVoteViewDemoUITests */,
377 | );
378 | };
379 | /* End PBXProject section */
380 |
381 | /* Begin PBXResourcesBuildPhase section */
382 | 366DC1BC1D65544700691A3B /* Resources */ = {
383 | isa = PBXResourcesBuildPhase;
384 | buildActionMask = 2147483647;
385 | files = (
386 | 366DC26B1D6B2CC800691A3B /* 格瓦拉投票效果3.gif in Resources */,
387 | 366DC2641D6AF65000691A3B /* 格瓦拉投票效果2.gif in Resources */,
388 | 366DC1D11D65544700691A3B /* LaunchScreen.storyboard in Resources */,
389 | 366DC1F51D6563DF00691A3B /* abc.plist in Resources */,
390 | 366DC1CE1D65544700691A3B /* Assets.xcassets in Resources */,
391 | 366DC2621D6AF65000691A3B /* 格瓦拉投票效果1.gif in Resources */,
392 | 366DC1CC1D65544700691A3B /* Main.storyboard in Resources */,
393 | );
394 | runOnlyForDeploymentPostprocessing = 0;
395 | };
396 | 366DC1D51D65544700691A3B /* Resources */ = {
397 | isa = PBXResourcesBuildPhase;
398 | buildActionMask = 2147483647;
399 | files = (
400 | );
401 | runOnlyForDeploymentPostprocessing = 0;
402 | };
403 | 366DC1E01D65544700691A3B /* Resources */ = {
404 | isa = PBXResourcesBuildPhase;
405 | buildActionMask = 2147483647;
406 | files = (
407 | );
408 | runOnlyForDeploymentPostprocessing = 0;
409 | };
410 | /* End PBXResourcesBuildPhase section */
411 |
412 | /* Begin PBXSourcesBuildPhase section */
413 | 366DC1BA1D65544700691A3B /* Sources */ = {
414 | isa = PBXSourcesBuildPhase;
415 | buildActionMask = 2147483647;
416 | files = (
417 | 36B6EEF31D6C1518005C3FBF /* NSObject+MJClass.m in Sources */,
418 | 36B6EEEF1D6C1518005C3FBF /* MJFoundation.m in Sources */,
419 | 366DC25B1D6A91FB00691A3B /* ZFVoteTableView.m in Sources */,
420 | 366DC2691D6AFCAE00691A3B /* README.md in Sources */,
421 | 366DC21C1D6581AB00691A3B /* ZFVoteModel.m in Sources */,
422 | 36B6EEF21D6C1518005C3FBF /* MJPropertyType.m in Sources */,
423 | 36B6EEF71D6C1518005C3FBF /* NSString+MJExtension.m in Sources */,
424 | 36B6EEF11D6C1518005C3FBF /* MJPropertyKey.m in Sources */,
425 | 366DC2201D65856A00691A3B /* ZFVoteCell.m in Sources */,
426 | 36B6EEF61D6C1518005C3FBF /* NSObject+MJProperty.m in Sources */,
427 | 366DC2551D66D43100691A3B /* ZFVoteView.m in Sources */,
428 | 366DC1C91D65544700691A3B /* ViewController.m in Sources */,
429 | 366DC1C61D65544700691A3B /* AppDelegate.m in Sources */,
430 | 36B6EEF01D6C1518005C3FBF /* MJProperty.m in Sources */,
431 | 36B6EEEE1D6C1518005C3FBF /* MJExtensionConst.m in Sources */,
432 | 36B6EEF41D6C1518005C3FBF /* NSObject+MJCoding.m in Sources */,
433 | 36B6EEF51D6C1518005C3FBF /* NSObject+MJKeyValue.m in Sources */,
434 | 366DC2231D6587AC00691A3B /* UIView+Extension.m in Sources */,
435 | 366DC2581D67509600691A3B /* ZFPercentBar.m in Sources */,
436 | 366DC1C31D65544700691A3B /* main.m in Sources */,
437 | );
438 | runOnlyForDeploymentPostprocessing = 0;
439 | };
440 | 366DC1D31D65544700691A3B /* Sources */ = {
441 | isa = PBXSourcesBuildPhase;
442 | buildActionMask = 2147483647;
443 | files = (
444 | 366DC1DC1D65544700691A3B /* ZFVoteViewDemoTests.m in Sources */,
445 | );
446 | runOnlyForDeploymentPostprocessing = 0;
447 | };
448 | 366DC1DE1D65544700691A3B /* Sources */ = {
449 | isa = PBXSourcesBuildPhase;
450 | buildActionMask = 2147483647;
451 | files = (
452 | 366DC1E71D65544700691A3B /* ZFVoteViewDemoUITests.m in Sources */,
453 | );
454 | runOnlyForDeploymentPostprocessing = 0;
455 | };
456 | /* End PBXSourcesBuildPhase section */
457 |
458 | /* Begin PBXTargetDependency section */
459 | 366DC1D91D65544700691A3B /* PBXTargetDependency */ = {
460 | isa = PBXTargetDependency;
461 | target = 366DC1BD1D65544700691A3B /* ZFVoteViewDemo */;
462 | targetProxy = 366DC1D81D65544700691A3B /* PBXContainerItemProxy */;
463 | };
464 | 366DC1E41D65544700691A3B /* PBXTargetDependency */ = {
465 | isa = PBXTargetDependency;
466 | target = 366DC1BD1D65544700691A3B /* ZFVoteViewDemo */;
467 | targetProxy = 366DC1E31D65544700691A3B /* PBXContainerItemProxy */;
468 | };
469 | /* End PBXTargetDependency section */
470 |
471 | /* Begin PBXVariantGroup section */
472 | 366DC1CA1D65544700691A3B /* Main.storyboard */ = {
473 | isa = PBXVariantGroup;
474 | children = (
475 | 366DC1CB1D65544700691A3B /* Base */,
476 | );
477 | name = Main.storyboard;
478 | sourceTree = "";
479 | };
480 | 366DC1CF1D65544700691A3B /* LaunchScreen.storyboard */ = {
481 | isa = PBXVariantGroup;
482 | children = (
483 | 366DC1D01D65544700691A3B /* Base */,
484 | );
485 | name = LaunchScreen.storyboard;
486 | sourceTree = "";
487 | };
488 | /* End PBXVariantGroup section */
489 |
490 | /* Begin XCBuildConfiguration section */
491 | 366DC1E91D65544700691A3B /* Debug */ = {
492 | isa = XCBuildConfiguration;
493 | buildSettings = {
494 | ALWAYS_SEARCH_USER_PATHS = NO;
495 | CLANG_ANALYZER_NONNULL = YES;
496 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
497 | CLANG_CXX_LIBRARY = "libc++";
498 | CLANG_ENABLE_MODULES = YES;
499 | CLANG_ENABLE_OBJC_ARC = YES;
500 | CLANG_WARN_BOOL_CONVERSION = YES;
501 | CLANG_WARN_CONSTANT_CONVERSION = YES;
502 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
503 | CLANG_WARN_EMPTY_BODY = YES;
504 | CLANG_WARN_ENUM_CONVERSION = YES;
505 | CLANG_WARN_INT_CONVERSION = YES;
506 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
507 | CLANG_WARN_UNREACHABLE_CODE = YES;
508 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
509 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
510 | COPY_PHASE_STRIP = NO;
511 | DEBUG_INFORMATION_FORMAT = dwarf;
512 | ENABLE_STRICT_OBJC_MSGSEND = YES;
513 | ENABLE_TESTABILITY = YES;
514 | GCC_C_LANGUAGE_STANDARD = gnu99;
515 | GCC_DYNAMIC_NO_PIC = NO;
516 | GCC_NO_COMMON_BLOCKS = YES;
517 | GCC_OPTIMIZATION_LEVEL = 0;
518 | GCC_PREPROCESSOR_DEFINITIONS = (
519 | "DEBUG=1",
520 | "$(inherited)",
521 | );
522 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
523 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
524 | GCC_WARN_UNDECLARED_SELECTOR = YES;
525 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
526 | GCC_WARN_UNUSED_FUNCTION = YES;
527 | GCC_WARN_UNUSED_VARIABLE = YES;
528 | IPHONEOS_DEPLOYMENT_TARGET = 9.3;
529 | MTL_ENABLE_DEBUG_INFO = YES;
530 | ONLY_ACTIVE_ARCH = YES;
531 | SDKROOT = iphoneos;
532 | TARGETED_DEVICE_FAMILY = "1,2";
533 | };
534 | name = Debug;
535 | };
536 | 366DC1EA1D65544700691A3B /* Release */ = {
537 | isa = XCBuildConfiguration;
538 | buildSettings = {
539 | ALWAYS_SEARCH_USER_PATHS = NO;
540 | CLANG_ANALYZER_NONNULL = YES;
541 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
542 | CLANG_CXX_LIBRARY = "libc++";
543 | CLANG_ENABLE_MODULES = YES;
544 | CLANG_ENABLE_OBJC_ARC = YES;
545 | CLANG_WARN_BOOL_CONVERSION = YES;
546 | CLANG_WARN_CONSTANT_CONVERSION = YES;
547 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
548 | CLANG_WARN_EMPTY_BODY = YES;
549 | CLANG_WARN_ENUM_CONVERSION = YES;
550 | CLANG_WARN_INT_CONVERSION = YES;
551 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
552 | CLANG_WARN_UNREACHABLE_CODE = YES;
553 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
554 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
555 | COPY_PHASE_STRIP = NO;
556 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
557 | ENABLE_NS_ASSERTIONS = NO;
558 | ENABLE_STRICT_OBJC_MSGSEND = YES;
559 | GCC_C_LANGUAGE_STANDARD = gnu99;
560 | GCC_NO_COMMON_BLOCKS = YES;
561 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
562 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
563 | GCC_WARN_UNDECLARED_SELECTOR = YES;
564 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
565 | GCC_WARN_UNUSED_FUNCTION = YES;
566 | GCC_WARN_UNUSED_VARIABLE = YES;
567 | IPHONEOS_DEPLOYMENT_TARGET = 9.3;
568 | MTL_ENABLE_DEBUG_INFO = NO;
569 | SDKROOT = iphoneos;
570 | TARGETED_DEVICE_FAMILY = "1,2";
571 | VALIDATE_PRODUCT = YES;
572 | };
573 | name = Release;
574 | };
575 | 366DC1EC1D65544700691A3B /* Debug */ = {
576 | isa = XCBuildConfiguration;
577 | buildSettings = {
578 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
579 | INFOPLIST_FILE = ZFVoteViewDemo/Info.plist;
580 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
581 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
582 | PRODUCT_BUNDLE_IDENTIFIER = zfbory.animateRaingBar.ZFVoteViewDemo;
583 | PRODUCT_NAME = "$(TARGET_NAME)";
584 | };
585 | name = Debug;
586 | };
587 | 366DC1ED1D65544700691A3B /* Release */ = {
588 | isa = XCBuildConfiguration;
589 | buildSettings = {
590 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
591 | INFOPLIST_FILE = ZFVoteViewDemo/Info.plist;
592 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
593 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
594 | PRODUCT_BUNDLE_IDENTIFIER = zfbory.animateRaingBar.ZFVoteViewDemo;
595 | PRODUCT_NAME = "$(TARGET_NAME)";
596 | };
597 | name = Release;
598 | };
599 | 366DC1EF1D65544700691A3B /* Debug */ = {
600 | isa = XCBuildConfiguration;
601 | buildSettings = {
602 | BUNDLE_LOADER = "$(TEST_HOST)";
603 | INFOPLIST_FILE = ZFVoteViewDemoTests/Info.plist;
604 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
605 | PRODUCT_BUNDLE_IDENTIFIER = zfbory.animateRaingBar.ZFVoteViewDemoTests;
606 | PRODUCT_NAME = "$(TARGET_NAME)";
607 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ZFVoteViewDemo.app/ZFVoteViewDemo";
608 | };
609 | name = Debug;
610 | };
611 | 366DC1F01D65544700691A3B /* Release */ = {
612 | isa = XCBuildConfiguration;
613 | buildSettings = {
614 | BUNDLE_LOADER = "$(TEST_HOST)";
615 | INFOPLIST_FILE = ZFVoteViewDemoTests/Info.plist;
616 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
617 | PRODUCT_BUNDLE_IDENTIFIER = zfbory.animateRaingBar.ZFVoteViewDemoTests;
618 | PRODUCT_NAME = "$(TARGET_NAME)";
619 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ZFVoteViewDemo.app/ZFVoteViewDemo";
620 | };
621 | name = Release;
622 | };
623 | 366DC1F21D65544700691A3B /* Debug */ = {
624 | isa = XCBuildConfiguration;
625 | buildSettings = {
626 | INFOPLIST_FILE = ZFVoteViewDemoUITests/Info.plist;
627 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
628 | PRODUCT_BUNDLE_IDENTIFIER = zfbory.animateRaingBar.ZFVoteViewDemoUITests;
629 | PRODUCT_NAME = "$(TARGET_NAME)";
630 | TEST_TARGET_NAME = ZFVoteViewDemo;
631 | };
632 | name = Debug;
633 | };
634 | 366DC1F31D65544700691A3B /* Release */ = {
635 | isa = XCBuildConfiguration;
636 | buildSettings = {
637 | INFOPLIST_FILE = ZFVoteViewDemoUITests/Info.plist;
638 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
639 | PRODUCT_BUNDLE_IDENTIFIER = zfbory.animateRaingBar.ZFVoteViewDemoUITests;
640 | PRODUCT_NAME = "$(TARGET_NAME)";
641 | TEST_TARGET_NAME = ZFVoteViewDemo;
642 | };
643 | name = Release;
644 | };
645 | /* End XCBuildConfiguration section */
646 |
647 | /* Begin XCConfigurationList section */
648 | 366DC1B91D65544700691A3B /* Build configuration list for PBXProject "ZFVoteViewDemo" */ = {
649 | isa = XCConfigurationList;
650 | buildConfigurations = (
651 | 366DC1E91D65544700691A3B /* Debug */,
652 | 366DC1EA1D65544700691A3B /* Release */,
653 | );
654 | defaultConfigurationIsVisible = 0;
655 | defaultConfigurationName = Release;
656 | };
657 | 366DC1EB1D65544700691A3B /* Build configuration list for PBXNativeTarget "ZFVoteViewDemo" */ = {
658 | isa = XCConfigurationList;
659 | buildConfigurations = (
660 | 366DC1EC1D65544700691A3B /* Debug */,
661 | 366DC1ED1D65544700691A3B /* Release */,
662 | );
663 | defaultConfigurationIsVisible = 0;
664 | defaultConfigurationName = Release;
665 | };
666 | 366DC1EE1D65544700691A3B /* Build configuration list for PBXNativeTarget "ZFVoteViewDemoTests" */ = {
667 | isa = XCConfigurationList;
668 | buildConfigurations = (
669 | 366DC1EF1D65544700691A3B /* Debug */,
670 | 366DC1F01D65544700691A3B /* Release */,
671 | );
672 | defaultConfigurationIsVisible = 0;
673 | defaultConfigurationName = Release;
674 | };
675 | 366DC1F11D65544700691A3B /* Build configuration list for PBXNativeTarget "ZFVoteViewDemoUITests" */ = {
676 | isa = XCConfigurationList;
677 | buildConfigurations = (
678 | 366DC1F21D65544700691A3B /* Debug */,
679 | 366DC1F31D65544700691A3B /* Release */,
680 | );
681 | defaultConfigurationIsVisible = 0;
682 | defaultConfigurationName = Release;
683 | };
684 | /* End XCConfigurationList section */
685 | };
686 | rootObject = 366DC1B61D65544700691A3B /* Project object */;
687 | }
688 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo.xcodeproj/project.xcworkspace/xcuserdata/dzmacbook.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZFbaby/ZFVoteViewDemo/dcf12ee9fd89b77ffffa7b7cbcfebb8e8a339b41/ZFVoteViewDemo.xcodeproj/project.xcworkspace/xcuserdata/dzmacbook.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/ZFVoteViewDemo.xcodeproj/xcuserdata/dzmacbook.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | ZFVoteViewDemo.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo.xcodeproj/xcuserdata/saitechuanmeigufenyouxiangongsi.xcuserdatad/xcschemes/ZFVoteViewDemo.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
43 |
49 |
50 |
51 |
52 |
53 |
59 |
60 |
61 |
62 |
63 |
64 |
74 |
76 |
82 |
83 |
84 |
85 |
86 |
87 |
93 |
95 |
101 |
102 |
103 |
104 |
106 |
107 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo.xcodeproj/xcuserdata/saitechuanmeigufenyouxiangongsi.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | ZFVoteViewDemo.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 366DC1BD1D65544700691A3B
16 |
17 | primary
18 |
19 |
20 | 366DC1D61D65544700691A3B
21 |
22 | primary
23 |
24 |
25 | 366DC1E11D65544700691A3B
26 |
27 | primary
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // ZFVoteViewDemo
4 | //
5 | // Created by MAC_PRO on 16/8/18.
6 | // Copyright © 2016年 ZFbory. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 |
16 | @end
17 |
18 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // ZFVoteViewDemo
4 | //
5 | // Created by MAC_PRO on 16/8/18.
6 | // Copyright © 2016年 ZFbory. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | @interface AppDelegate ()
12 |
13 | @end
14 |
15 | @implementation AppDelegate
16 |
17 |
18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
19 | // Override point for customization after application launch.
20 | return YES;
21 | }
22 |
23 | - (void)applicationWillResignActive:(UIApplication *)application {
24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
26 | }
27 |
28 | - (void)applicationDidEnterBackground:(UIApplication *)application {
29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
31 | }
32 |
33 | - (void)applicationWillEnterForeground:(UIApplication *)application {
34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
35 | }
36 |
37 | - (void)applicationDidBecomeActive:(UIApplication *)application {
38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
39 | }
40 |
41 | - (void)applicationWillTerminate:(UIApplication *)application {
42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
43 | }
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/Assets.xcassets/AppIcon.appiconset/AppIcon29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZFbaby/ZFVoteViewDemo/dcf12ee9fd89b77ffffa7b7cbcfebb8e8a339b41/ZFVoteViewDemo/Assets.xcassets/AppIcon.appiconset/AppIcon29x29@2x.png
--------------------------------------------------------------------------------
/ZFVoteViewDemo/Assets.xcassets/AppIcon.appiconset/AppIcon29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZFbaby/ZFVoteViewDemo/dcf12ee9fd89b77ffffa7b7cbcfebb8e8a339b41/ZFVoteViewDemo/Assets.xcassets/AppIcon.appiconset/AppIcon29x29@3x.png
--------------------------------------------------------------------------------
/ZFVoteViewDemo/Assets.xcassets/AppIcon.appiconset/AppIcon40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZFbaby/ZFVoteViewDemo/dcf12ee9fd89b77ffffa7b7cbcfebb8e8a339b41/ZFVoteViewDemo/Assets.xcassets/AppIcon.appiconset/AppIcon40x40@2x.png
--------------------------------------------------------------------------------
/ZFVoteViewDemo/Assets.xcassets/AppIcon.appiconset/AppIcon40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZFbaby/ZFVoteViewDemo/dcf12ee9fd89b77ffffa7b7cbcfebb8e8a339b41/ZFVoteViewDemo/Assets.xcassets/AppIcon.appiconset/AppIcon40x40@3x.png
--------------------------------------------------------------------------------
/ZFVoteViewDemo/Assets.xcassets/AppIcon.appiconset/AppIcon60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZFbaby/ZFVoteViewDemo/dcf12ee9fd89b77ffffa7b7cbcfebb8e8a339b41/ZFVoteViewDemo/Assets.xcassets/AppIcon.appiconset/AppIcon60x60@2x.png
--------------------------------------------------------------------------------
/ZFVoteViewDemo/Assets.xcassets/AppIcon.appiconset/AppIcon60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZFbaby/ZFVoteViewDemo/dcf12ee9fd89b77ffffa7b7cbcfebb8e8a339b41/ZFVoteViewDemo/Assets.xcassets/AppIcon.appiconset/AppIcon60x60@3x.png
--------------------------------------------------------------------------------
/ZFVoteViewDemo/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "size" : "40x40",
20 | "idiom" : "iphone",
21 | "filename" : "AppIcon40x40@3x.png",
22 | "scale" : "3x"
23 | },
24 | {
25 | "size" : "60x60",
26 | "idiom" : "iphone",
27 | "filename" : "AppIcon60x60@2x.png",
28 | "scale" : "2x"
29 | },
30 | {
31 | "size" : "60x60",
32 | "idiom" : "iphone",
33 | "filename" : "AppIcon60x60@3x.png",
34 | "scale" : "3x"
35 | },
36 | {
37 | "idiom" : "ipad",
38 | "size" : "29x29",
39 | "scale" : "1x"
40 | },
41 | {
42 | "idiom" : "ipad",
43 | "size" : "29x29",
44 | "scale" : "2x"
45 | },
46 | {
47 | "idiom" : "ipad",
48 | "size" : "40x40",
49 | "scale" : "1x"
50 | },
51 | {
52 | "size" : "40x40",
53 | "idiom" : "ipad",
54 | "filename" : "AppIcon40x40@2x.png",
55 | "scale" : "2x"
56 | },
57 | {
58 | "idiom" : "ipad",
59 | "size" : "76x76",
60 | "scale" : "1x"
61 | },
62 | {
63 | "idiom" : "ipad",
64 | "size" : "76x76",
65 | "scale" : "2x"
66 | },
67 | {
68 | "idiom" : "ipad",
69 | "size" : "83.5x83.5",
70 | "scale" : "2x"
71 | },
72 | {
73 | "size" : "24x24",
74 | "idiom" : "watch",
75 | "scale" : "2x",
76 | "role" : "notificationCenter",
77 | "subtype" : "38mm"
78 | },
79 | {
80 | "size" : "27.5x27.5",
81 | "idiom" : "watch",
82 | "scale" : "2x",
83 | "role" : "notificationCenter",
84 | "subtype" : "42mm"
85 | },
86 | {
87 | "size" : "29x29",
88 | "idiom" : "watch",
89 | "filename" : "AppIcon29x29@2x.png",
90 | "role" : "companionSettings",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "29x29",
95 | "idiom" : "watch",
96 | "filename" : "AppIcon29x29@3x.png",
97 | "role" : "companionSettings",
98 | "scale" : "3x"
99 | },
100 | {
101 | "size" : "40x40",
102 | "idiom" : "watch",
103 | "scale" : "2x",
104 | "role" : "appLauncher",
105 | "subtype" : "38mm"
106 | },
107 | {
108 | "size" : "86x86",
109 | "idiom" : "watch",
110 | "scale" : "2x",
111 | "role" : "quickLook",
112 | "subtype" : "38mm"
113 | },
114 | {
115 | "size" : "98x98",
116 | "idiom" : "watch",
117 | "scale" : "2x",
118 | "role" : "quickLook",
119 | "subtype" : "42mm"
120 | }
121 | ],
122 | "info" : {
123 | "version" : 1,
124 | "author" : "xcode"
125 | }
126 | }
--------------------------------------------------------------------------------
/ZFVoteViewDemo/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/ZFVoteViewDemo/Assets.xcassets/Like-Blue.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "Like-Blue.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/ZFVoteViewDemo/Assets.xcassets/Like-Blue.imageset/Like-Blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZFbaby/ZFVoteViewDemo/dcf12ee9fd89b77ffffa7b7cbcfebb8e8a339b41/ZFVoteViewDemo/Assets.xcassets/Like-Blue.imageset/Like-Blue.png
--------------------------------------------------------------------------------
/ZFVoteViewDemo/Assets.xcassets/Like-PlaceHold.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "Like-PlaceHold.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/ZFVoteViewDemo/Assets.xcassets/Like-PlaceHold.imageset/Like-PlaceHold.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZFbaby/ZFVoteViewDemo/dcf12ee9fd89b77ffffa7b7cbcfebb8e8a339b41/ZFVoteViewDemo/Assets.xcassets/Like-PlaceHold.imageset/Like-PlaceHold.png
--------------------------------------------------------------------------------
/ZFVoteViewDemo/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/MJExtension/MJExtension.h:
--------------------------------------------------------------------------------
1 | //
2 | // MJExtension.h
3 | // MJExtension
4 | //
5 | // Created by mj on 14-1-15.
6 | // Copyright (c) 2014年 小码哥. All rights reserved.
7 | // 代码地址:https://github.com/CoderMJLee/MJExtension
8 | // 代码地址:http://code4app.com/ios/%E5%AD%97%E5%85%B8-JSON-%E4%B8%8E%E6%A8%A1%E5%9E%8B%E7%9A%84%E8%BD%AC%E6%8D%A2/5339992a933bf062608b4c57
9 |
10 | #import "NSObject+MJCoding.h"
11 | #import "NSObject+MJProperty.h"
12 | #import "NSObject+MJClass.h"
13 | #import "NSObject+MJKeyValue.h"
14 | #import "NSString+MJExtension.h"
15 | #import "MJExtensionConst.h"
--------------------------------------------------------------------------------
/ZFVoteViewDemo/MJExtension/MJExtensionConst.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef __MJExtensionConst__H__
3 | #define __MJExtensionConst__H__
4 |
5 | #import
6 |
7 | // 过期
8 | #define MJExtensionDeprecated(instead) NS_DEPRECATED(2_0, 2_0, 2_0, 2_0, instead)
9 |
10 | // 构建错误
11 | #define MJExtensionBuildError(clazz, msg) \
12 | NSError *error = [NSError errorWithDomain:msg code:250 userInfo:nil]; \
13 | [clazz setMj_error:error];
14 |
15 | // 日志输出
16 | #ifdef DEBUG
17 | #define MJExtensionLog(...) NSLog(__VA_ARGS__)
18 | #else
19 | #define MJExtensionLog(...)
20 | #endif
21 |
22 | /**
23 | * 断言
24 | * @param condition 条件
25 | * @param returnValue 返回值
26 | */
27 | #define MJExtensionAssertError(condition, returnValue, clazz, msg) \
28 | [clazz setMj_error:nil]; \
29 | if ((condition) == NO) { \
30 | MJExtensionBuildError(clazz, msg); \
31 | return returnValue;\
32 | }
33 |
34 | #define MJExtensionAssert2(condition, returnValue) \
35 | if ((condition) == NO) return returnValue;
36 |
37 | /**
38 | * 断言
39 | * @param condition 条件
40 | */
41 | #define MJExtensionAssert(condition) MJExtensionAssert2(condition, )
42 |
43 | /**
44 | * 断言
45 | * @param param 参数
46 | * @param returnValue 返回值
47 | */
48 | #define MJExtensionAssertParamNotNil2(param, returnValue) \
49 | MJExtensionAssert2((param) != nil, returnValue)
50 |
51 | /**
52 | * 断言
53 | * @param param 参数
54 | */
55 | #define MJExtensionAssertParamNotNil(param) MJExtensionAssertParamNotNil2(param, )
56 |
57 | /**
58 | * 打印所有的属性
59 | */
60 | #define MJLogAllIvars \
61 | -(NSString *)description \
62 | { \
63 | return [self mj_keyValues].description; \
64 | }
65 | #define MJExtensionLogAllProperties MJLogAllIvars
66 |
67 | /**
68 | * 类型(属性类型)
69 | */
70 | extern NSString *const MJPropertyTypeInt;
71 | extern NSString *const MJPropertyTypeShort;
72 | extern NSString *const MJPropertyTypeFloat;
73 | extern NSString *const MJPropertyTypeDouble;
74 | extern NSString *const MJPropertyTypeLong;
75 | extern NSString *const MJPropertyTypeLongLong;
76 | extern NSString *const MJPropertyTypeChar;
77 | extern NSString *const MJPropertyTypeBOOL1;
78 | extern NSString *const MJPropertyTypeBOOL2;
79 | extern NSString *const MJPropertyTypePointer;
80 |
81 | extern NSString *const MJPropertyTypeIvar;
82 | extern NSString *const MJPropertyTypeMethod;
83 | extern NSString *const MJPropertyTypeBlock;
84 | extern NSString *const MJPropertyTypeClass;
85 | extern NSString *const MJPropertyTypeSEL;
86 | extern NSString *const MJPropertyTypeId;
87 |
88 | #endif
--------------------------------------------------------------------------------
/ZFVoteViewDemo/MJExtension/MJExtensionConst.m:
--------------------------------------------------------------------------------
1 | #ifndef __MJExtensionConst__M__
2 | #define __MJExtensionConst__M__
3 |
4 | #import
5 |
6 | /**
7 | * 成员变量类型(属性类型)
8 | */
9 | NSString *const MJPropertyTypeInt = @"i";
10 | NSString *const MJPropertyTypeShort = @"s";
11 | NSString *const MJPropertyTypeFloat = @"f";
12 | NSString *const MJPropertyTypeDouble = @"d";
13 | NSString *const MJPropertyTypeLong = @"l";
14 | NSString *const MJPropertyTypeLongLong = @"q";
15 | NSString *const MJPropertyTypeChar = @"c";
16 | NSString *const MJPropertyTypeBOOL1 = @"c";
17 | NSString *const MJPropertyTypeBOOL2 = @"b";
18 | NSString *const MJPropertyTypePointer = @"*";
19 |
20 | NSString *const MJPropertyTypeIvar = @"^{objc_ivar=}";
21 | NSString *const MJPropertyTypeMethod = @"^{objc_method=}";
22 | NSString *const MJPropertyTypeBlock = @"@?";
23 | NSString *const MJPropertyTypeClass = @"#";
24 | NSString *const MJPropertyTypeSEL = @":";
25 | NSString *const MJPropertyTypeId = @"@";
26 |
27 | #endif
--------------------------------------------------------------------------------
/ZFVoteViewDemo/MJExtension/MJFoundation.h:
--------------------------------------------------------------------------------
1 | //
2 | // MJFoundation.h
3 | // MJExtensionExample
4 | //
5 | // Created by MJ Lee on 14/7/16.
6 | // Copyright (c) 2014年 小码哥. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface MJFoundation : NSObject
12 | + (BOOL)isClassFromFoundation:(Class)c;
13 | @end
14 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/MJExtension/MJFoundation.m:
--------------------------------------------------------------------------------
1 | //
2 | // MJFoundation.m
3 | // MJExtensionExample
4 | //
5 | // Created by MJ Lee on 14/7/16.
6 | // Copyright (c) 2014年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJFoundation.h"
10 | #import "MJExtensionConst.h"
11 | #import
12 |
13 | static NSSet *foundationClasses_;
14 |
15 | @implementation MJFoundation
16 |
17 | + (NSSet *)foundationClasses
18 | {
19 | if (foundationClasses_ == nil) {
20 | // 集合中没有NSObject,因为几乎所有的类都是继承自NSObject,具体是不是NSObject需要特殊判断
21 | foundationClasses_ = [NSSet setWithObjects:
22 | [NSURL class],
23 | [NSDate class],
24 | [NSValue class],
25 | [NSData class],
26 | [NSError class],
27 | [NSArray class],
28 | [NSDictionary class],
29 | [NSString class],
30 | [NSAttributedString class], nil];
31 | }
32 | return foundationClasses_;
33 | }
34 |
35 | + (BOOL)isClassFromFoundation:(Class)c
36 | {
37 | if (c == [NSObject class] || c == [NSManagedObject class]) return YES;
38 |
39 | __block BOOL result = NO;
40 | [[self foundationClasses] enumerateObjectsUsingBlock:^(Class foundationClass, BOOL *stop) {
41 | if ([c isSubclassOfClass:foundationClass]) {
42 | result = YES;
43 | *stop = YES;
44 | }
45 | }];
46 | return result;
47 | }
48 | @end
49 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/MJExtension/MJProperty.h:
--------------------------------------------------------------------------------
1 | //
2 | // MJProperty.h
3 | // MJExtensionExample
4 | //
5 | // Created by MJ Lee on 15/4/17.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | // 包装一个成员属性
8 |
9 | #import
10 | #import
11 | #import "MJPropertyType.h"
12 | #import "MJPropertyKey.h"
13 |
14 | /**
15 | * 包装一个成员
16 | */
17 | @interface MJProperty : NSObject
18 | /** 成员属性 */
19 | @property (nonatomic, assign) objc_property_t property;
20 | /** 成员属性的名字 */
21 | @property (nonatomic, readonly) NSString *name;
22 |
23 | /** 成员属性的类型 */
24 | @property (nonatomic, readonly) MJPropertyType *type;
25 | /** 成员属性来源于哪个类(可能是父类) */
26 | @property (nonatomic, assign) Class srcClass;
27 |
28 | /**** 同一个成员属性 - 父类和子类的行为可能不一致(originKey、propertyKeys、objectClassInArray) ****/
29 | /** 设置最原始的key */
30 | - (void)setOriginKey:(id)originKey forClass:(Class)c;
31 | /** 对应着字典中的多级key(里面存放的数组,数组里面都是MJPropertyKey对象) */
32 | - (NSArray *)propertyKeysForClass:(Class)c;
33 |
34 | /** 模型数组中的模型类型 */
35 | - (void)setObjectClassInArray:(Class)objectClass forClass:(Class)c;
36 | - (Class)objectClassInArrayForClass:(Class)c;
37 | /**** 同一个成员变量 - 父类和子类的行为可能不一致(key、keys、objectClassInArray) ****/
38 |
39 | /**
40 | * 设置object的成员变量值
41 | */
42 | - (void)setValue:(id)value forObject:(id)object;
43 | /**
44 | * 得到object的成员属性值
45 | */
46 | - (id)valueForObject:(id)object;
47 |
48 | /**
49 | * 初始化
50 | */
51 | + (instancetype)cachedPropertyWithProperty:(objc_property_t)property;
52 |
53 | @end
54 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/MJExtension/MJProperty.m:
--------------------------------------------------------------------------------
1 | //
2 | // MJProperty.m
3 | // MJExtensionExample
4 | //
5 | // Created by MJ Lee on 15/4/17.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJProperty.h"
10 | #import "MJFoundation.h"
11 | #import "MJExtensionConst.h"
12 | #import
13 |
14 | @interface MJProperty()
15 | @property (strong, nonatomic) NSMutableDictionary *propertyKeysDict;
16 | @property (strong, nonatomic) NSMutableDictionary *objectClassInArrayDict;
17 | @end
18 |
19 | @implementation MJProperty
20 |
21 | #pragma mark - 懒加载
22 | - (NSMutableDictionary *)propertyKeysDict
23 | {
24 | if (!_propertyKeysDict) {
25 | _propertyKeysDict = [NSMutableDictionary dictionary];
26 | }
27 | return _propertyKeysDict;
28 | }
29 |
30 | - (NSMutableDictionary *)objectClassInArrayDict
31 | {
32 | if (!_objectClassInArrayDict) {
33 | _objectClassInArrayDict = [NSMutableDictionary dictionary];
34 | }
35 | return _objectClassInArrayDict;
36 | }
37 |
38 | #pragma mark - 缓存
39 | + (instancetype)cachedPropertyWithProperty:(objc_property_t)property
40 | {
41 | MJProperty *propertyObj = objc_getAssociatedObject(self, property);
42 | if (propertyObj == nil) {
43 | propertyObj = [[self alloc] init];
44 | propertyObj.property = property;
45 | objc_setAssociatedObject(self, property, propertyObj, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
46 | }
47 | return propertyObj;
48 | }
49 |
50 | #pragma mark - 公共方法
51 | - (void)setProperty:(objc_property_t)property
52 | {
53 | _property = property;
54 |
55 | MJExtensionAssertParamNotNil(property);
56 |
57 | // 1.属性名
58 | _name = @(property_getName(property));
59 |
60 | // 2.成员类型
61 | NSString *attrs = @(property_getAttributes(property));
62 | NSUInteger dotLoc = [attrs rangeOfString:@","].location;
63 | NSString *code = nil;
64 | NSUInteger loc = 1;
65 | if (dotLoc == NSNotFound) { // 没有,
66 | code = [attrs substringFromIndex:loc];
67 | } else {
68 | code = [attrs substringWithRange:NSMakeRange(loc, dotLoc - loc)];
69 | }
70 | _type = [MJPropertyType cachedTypeWithCode:code];
71 | }
72 |
73 | /**
74 | * 获得成员变量的值
75 | */
76 | - (id)valueForObject:(id)object
77 | {
78 | if (self.type.KVCDisabled) return [NSNull null];
79 | return [object valueForKey:self.name];
80 | }
81 |
82 | /**
83 | * 设置成员变量的值
84 | */
85 | - (void)setValue:(id)value forObject:(id)object
86 | {
87 | if (self.type.KVCDisabled || value == nil) return;
88 | [object setValue:value forKey:self.name];
89 | }
90 |
91 | /**
92 | * 通过字符串key创建对应的keys
93 | */
94 | - (NSArray *)propertyKeysWithStringKey:(NSString *)stringKey
95 | {
96 | if (stringKey.length == 0) return nil;
97 |
98 | NSMutableArray *propertyKeys = [NSMutableArray array];
99 | // 如果有多级映射
100 | NSArray *oldKeys = [stringKey componentsSeparatedByString:@"."];
101 |
102 | for (NSString *oldKey in oldKeys) {
103 | NSUInteger start = [oldKey rangeOfString:@"["].location;
104 | if (start != NSNotFound) { // 有索引的key
105 | NSString *prefixKey = [oldKey substringToIndex:start];
106 | NSString *indexKey = prefixKey;
107 | if (prefixKey.length) {
108 | MJPropertyKey *propertyKey = [[MJPropertyKey alloc] init];
109 | propertyKey.name = prefixKey;
110 | [propertyKeys addObject:propertyKey];
111 |
112 | indexKey = [oldKey stringByReplacingOccurrencesOfString:prefixKey withString:@""];
113 | }
114 |
115 | /** 解析索引 **/
116 | // 元素
117 | NSArray *cmps = [[indexKey stringByReplacingOccurrencesOfString:@"[" withString:@""] componentsSeparatedByString:@"]"];
118 | for (NSInteger i = 0; i
10 |
11 | typedef enum {
12 | MJPropertyKeyTypeDictionary = 0, // 字典的key
13 | MJPropertyKeyTypeArray // 数组的key
14 | } MJPropertyKeyType;
15 |
16 | /**
17 | * 属性的key
18 | */
19 | @interface MJPropertyKey : NSObject
20 | /** key的名字 */
21 | @property (copy, nonatomic) NSString *name;
22 | /** key的种类,可能是@"10",可能是@"age" */
23 | @property (assign, nonatomic) MJPropertyKeyType type;
24 |
25 | /**
26 | * 根据当前的key,也就是name,从object(字典或者数组)中取值
27 | */
28 | - (id)valueInObject:(id)object;
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/MJExtension/MJPropertyKey.m:
--------------------------------------------------------------------------------
1 | //
2 | // MJPropertyKey.m
3 | // MJExtensionExample
4 | //
5 | // Created by MJ Lee on 15/8/11.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJPropertyKey.h"
10 |
11 | @implementation MJPropertyKey
12 |
13 | - (id)valueInObject:(id)object
14 | {
15 | if ([object isKindOfClass:[NSDictionary class]] && self.type == MJPropertyKeyTypeDictionary) {
16 | return object[self.name];
17 | } else if ([object isKindOfClass:[NSArray class]] && self.type == MJPropertyKeyTypeArray) {
18 | NSArray *array = object;
19 | NSUInteger index = self.name.intValue;
20 | if (index < array.count) return array[index];
21 | return nil;
22 | }
23 | return nil;
24 | }
25 | @end
26 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/MJExtension/MJPropertyType.h:
--------------------------------------------------------------------------------
1 | //
2 | // MJPropertyType.h
3 | // MJExtension
4 | //
5 | // Created by mj on 14-1-15.
6 | // Copyright (c) 2014年 小码哥. All rights reserved.
7 | // 包装一种类型
8 |
9 | #import
10 |
11 | /**
12 | * 包装一种类型
13 | */
14 | @interface MJPropertyType : NSObject
15 | /** 类型标识符 */
16 | @property (nonatomic, copy) NSString *code;
17 |
18 | /** 是否为id类型 */
19 | @property (nonatomic, readonly, getter=isIdType) BOOL idType;
20 |
21 | /** 是否为基本数字类型:int、float等 */
22 | @property (nonatomic, readonly, getter=isNumberType) BOOL numberType;
23 |
24 | /** 是否为BOOL类型 */
25 | @property (nonatomic, readonly, getter=isBoolType) BOOL boolType;
26 |
27 | /** 对象类型(如果是基本数据类型,此值为nil) */
28 | @property (nonatomic, readonly) Class typeClass;
29 |
30 | /** 类型是否来自于Foundation框架,比如NSString、NSArray */
31 | @property (nonatomic, readonly, getter = isFromFoundation) BOOL fromFoundation;
32 | /** 类型是否不支持KVC */
33 | @property (nonatomic, readonly, getter = isKVCDisabled) BOOL KVCDisabled;
34 |
35 | /**
36 | * 获得缓存的类型对象
37 | */
38 | + (instancetype)cachedTypeWithCode:(NSString *)code;
39 | @end
--------------------------------------------------------------------------------
/ZFVoteViewDemo/MJExtension/MJPropertyType.m:
--------------------------------------------------------------------------------
1 | //
2 | // MJPropertyType.m
3 | // MJExtension
4 | //
5 | // Created by mj on 14-1-15.
6 | // Copyright (c) 2014年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJPropertyType.h"
10 | #import "MJExtension.h"
11 | #import "MJFoundation.h"
12 | #import "MJExtensionConst.h"
13 |
14 | @implementation MJPropertyType
15 |
16 | static NSMutableDictionary *types_;
17 | + (void)initialize
18 | {
19 | types_ = [NSMutableDictionary dictionary];
20 | }
21 |
22 | + (instancetype)cachedTypeWithCode:(NSString *)code
23 | {
24 | MJExtensionAssertParamNotNil2(code, nil);
25 |
26 | MJPropertyType *type = types_[code];
27 | if (type == nil) {
28 | type = [[self alloc] init];
29 | type.code = code;
30 | types_[code] = type;
31 | }
32 | return type;
33 | }
34 |
35 | #pragma mark - 公共方法
36 | - (void)setCode:(NSString *)code
37 | {
38 | _code = code;
39 |
40 | MJExtensionAssertParamNotNil(code);
41 |
42 | if ([code isEqualToString:MJPropertyTypeId]) {
43 | _idType = YES;
44 | } else if (code.length == 0) {
45 | _KVCDisabled = YES;
46 | } else if (code.length > 3 && [code hasPrefix:@"@\""]) {
47 | // 去掉@"和",截取中间的类型名称
48 | _code = [code substringWithRange:NSMakeRange(2, code.length - 3)];
49 | _typeClass = NSClassFromString(_code);
50 | _fromFoundation = [MJFoundation isClassFromFoundation:_typeClass];
51 | _numberType = [_typeClass isSubclassOfClass:[NSNumber class]];
52 |
53 | } else if ([code isEqualToString:MJPropertyTypeSEL] ||
54 | [code isEqualToString:MJPropertyTypeIvar] ||
55 | [code isEqualToString:MJPropertyTypeMethod]) {
56 | _KVCDisabled = YES;
57 | }
58 |
59 | // 是否为数字类型
60 | NSString *lowerCode = _code.lowercaseString;
61 | NSArray *numberTypes = @[MJPropertyTypeInt, MJPropertyTypeShort, MJPropertyTypeBOOL1, MJPropertyTypeBOOL2, MJPropertyTypeFloat, MJPropertyTypeDouble, MJPropertyTypeLong, MJPropertyTypeLongLong, MJPropertyTypeChar];
62 | if ([numberTypes containsObject:lowerCode]) {
63 | _numberType = YES;
64 |
65 | if ([lowerCode isEqualToString:MJPropertyTypeBOOL1]
66 | || [lowerCode isEqualToString:MJPropertyTypeBOOL2]) {
67 | _boolType = YES;
68 | }
69 | }
70 | }
71 | @end
72 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/MJExtension/NSObject+MJClass.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+MJClass.h
3 | // MJExtensionExample
4 | //
5 | // Created by MJ Lee on 15/8/11.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | /**
12 | * 遍历所有类的block(父类)
13 | */
14 | typedef void (^MJClassesEnumeration)(Class c, BOOL *stop);
15 |
16 | /** 这个数组中的属性名才会进行字典和模型的转换 */
17 | typedef NSArray * (^MJAllowedPropertyNames)();
18 | /** 这个数组中的属性名才会进行归档 */
19 | typedef NSArray * (^MJAllowedCodingPropertyNames)();
20 |
21 | /** 这个数组中的属性名将会被忽略:不进行字典和模型的转换 */
22 | typedef NSArray * (^MJIgnoredPropertyNames)();
23 | /** 这个数组中的属性名将会被忽略:不进行归档 */
24 | typedef NSArray * (^MJIgnoredCodingPropertyNames)();
25 |
26 | /**
27 | * 类相关的扩展
28 | */
29 | @interface NSObject (MJClass)
30 | /**
31 | * 遍历所有的类
32 | */
33 | + (void)mj_enumerateClasses:(MJClassesEnumeration)enumeration;
34 | + (void)mj_enumerateAllClasses:(MJClassesEnumeration)enumeration;
35 |
36 | #pragma mark - 属性白名单配置
37 | /**
38 | * 这个数组中的属性名才会进行字典和模型的转换
39 | *
40 | * @param allowedPropertyNames 这个数组中的属性名才会进行字典和模型的转换
41 | */
42 | + (void)mj_setupAllowedPropertyNames:(MJAllowedPropertyNames)allowedPropertyNames;
43 |
44 | /**
45 | * 这个数组中的属性名才会进行字典和模型的转换
46 | */
47 | + (NSMutableArray *)mj_totalAllowedPropertyNames;
48 |
49 | #pragma mark - 属性黑名单配置
50 | /**
51 | * 这个数组中的属性名将会被忽略:不进行字典和模型的转换
52 | *
53 | * @param ignoredPropertyNames 这个数组中的属性名将会被忽略:不进行字典和模型的转换
54 | */
55 | + (void)mj_setupIgnoredPropertyNames:(MJIgnoredPropertyNames)ignoredPropertyNames;
56 |
57 | /**
58 | * 这个数组中的属性名将会被忽略:不进行字典和模型的转换
59 | */
60 | + (NSMutableArray *)mj_totalIgnoredPropertyNames;
61 |
62 | #pragma mark - 归档属性白名单配置
63 | /**
64 | * 这个数组中的属性名才会进行归档
65 | *
66 | * @param allowedCodingPropertyNames 这个数组中的属性名才会进行归档
67 | */
68 | + (void)mj_setupAllowedCodingPropertyNames:(MJAllowedCodingPropertyNames)allowedCodingPropertyNames;
69 |
70 | /**
71 | * 这个数组中的属性名才会进行字典和模型的转换
72 | */
73 | + (NSMutableArray *)mj_totalAllowedCodingPropertyNames;
74 |
75 | #pragma mark - 归档属性黑名单配置
76 | /**
77 | * 这个数组中的属性名将会被忽略:不进行归档
78 | *
79 | * @param ignoredCodingPropertyNames 这个数组中的属性名将会被忽略:不进行归档
80 | */
81 | + (void)mj_setupIgnoredCodingPropertyNames:(MJIgnoredCodingPropertyNames)ignoredCodingPropertyNames;
82 |
83 | /**
84 | * 这个数组中的属性名将会被忽略:不进行归档
85 | */
86 | + (NSMutableArray *)mj_totalIgnoredCodingPropertyNames;
87 |
88 | #pragma mark - 内部使用
89 | + (void)mj_setupBlockReturnValue:(id (^)())block key:(const char *)key;
90 | @end
91 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/MJExtension/NSObject+MJClass.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+MJClass.m
3 | // MJExtensionExample
4 | //
5 | // Created by MJ Lee on 15/8/11.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "NSObject+MJClass.h"
10 | #import "NSObject+MJCoding.h"
11 | #import "NSObject+MJKeyValue.h"
12 | #import "MJFoundation.h"
13 | #import
14 |
15 | static const char MJAllowedPropertyNamesKey = '\0';
16 | static const char MJIgnoredPropertyNamesKey = '\0';
17 | static const char MJAllowedCodingPropertyNamesKey = '\0';
18 | static const char MJIgnoredCodingPropertyNamesKey = '\0';
19 |
20 | static NSMutableDictionary *allowedPropertyNamesDict_;
21 | static NSMutableDictionary *ignoredPropertyNamesDict_;
22 | static NSMutableDictionary *allowedCodingPropertyNamesDict_;
23 | static NSMutableDictionary *ignoredCodingPropertyNamesDict_;
24 |
25 | @implementation NSObject (MJClass)
26 |
27 | + (void)load
28 | {
29 | allowedPropertyNamesDict_ = [NSMutableDictionary dictionary];
30 | ignoredPropertyNamesDict_ = [NSMutableDictionary dictionary];
31 | allowedCodingPropertyNamesDict_ = [NSMutableDictionary dictionary];
32 | ignoredCodingPropertyNamesDict_ = [NSMutableDictionary dictionary];
33 | }
34 |
35 | + (NSMutableDictionary *)dictForKey:(const void *)key
36 | {
37 | if (key == &MJAllowedPropertyNamesKey) return allowedPropertyNamesDict_;
38 | if (key == &MJIgnoredPropertyNamesKey) return ignoredPropertyNamesDict_;
39 | if (key == &MJAllowedCodingPropertyNamesKey) return allowedCodingPropertyNamesDict_;
40 | if (key == &MJIgnoredCodingPropertyNamesKey) return ignoredCodingPropertyNamesDict_;
41 | return nil;
42 | }
43 |
44 | + (void)mj_enumerateClasses:(MJClassesEnumeration)enumeration
45 | {
46 | // 1.没有block就直接返回
47 | if (enumeration == nil) return;
48 |
49 | // 2.停止遍历的标记
50 | BOOL stop = NO;
51 |
52 | // 3.当前正在遍历的类
53 | Class c = self;
54 |
55 | // 4.开始遍历每一个类
56 | while (c && !stop) {
57 | // 4.1.执行操作
58 | enumeration(c, &stop);
59 |
60 | // 4.2.获得父类
61 | c = class_getSuperclass(c);
62 |
63 | if ([MJFoundation isClassFromFoundation:c]) break;
64 | }
65 | }
66 |
67 | + (void)mj_enumerateAllClasses:(MJClassesEnumeration)enumeration
68 | {
69 | // 1.没有block就直接返回
70 | if (enumeration == nil) return;
71 |
72 | // 2.停止遍历的标记
73 | BOOL stop = NO;
74 |
75 | // 3.当前正在遍历的类
76 | Class c = self;
77 |
78 | // 4.开始遍历每一个类
79 | while (c && !stop) {
80 | // 4.1.执行操作
81 | enumeration(c, &stop);
82 |
83 | // 4.2.获得父类
84 | c = class_getSuperclass(c);
85 | }
86 | }
87 |
88 | #pragma mark - 属性黑名单配置
89 | + (void)mj_setupIgnoredPropertyNames:(MJIgnoredPropertyNames)ignoredPropertyNames
90 | {
91 | [self mj_setupBlockReturnValue:ignoredPropertyNames key:&MJIgnoredPropertyNamesKey];
92 | }
93 |
94 | + (NSMutableArray *)mj_totalIgnoredPropertyNames
95 | {
96 | return [self mj_totalObjectsWithSelector:@selector(mj_ignoredPropertyNames) key:&MJIgnoredPropertyNamesKey];
97 | }
98 |
99 | #pragma mark - 归档属性黑名单配置
100 | + (void)mj_setupIgnoredCodingPropertyNames:(MJIgnoredCodingPropertyNames)ignoredCodingPropertyNames
101 | {
102 | [self mj_setupBlockReturnValue:ignoredCodingPropertyNames key:&MJIgnoredCodingPropertyNamesKey];
103 | }
104 |
105 | + (NSMutableArray *)mj_totalIgnoredCodingPropertyNames
106 | {
107 | return [self mj_totalObjectsWithSelector:@selector(mj_ignoredCodingPropertyNames) key:&MJIgnoredCodingPropertyNamesKey];
108 | }
109 |
110 | #pragma mark - 属性白名单配置
111 | + (void)mj_setupAllowedPropertyNames:(MJAllowedPropertyNames)allowedPropertyNames;
112 | {
113 | [self mj_setupBlockReturnValue:allowedPropertyNames key:&MJAllowedPropertyNamesKey];
114 | }
115 |
116 | + (NSMutableArray *)mj_totalAllowedPropertyNames
117 | {
118 | return [self mj_totalObjectsWithSelector:@selector(mj_allowedPropertyNames) key:&MJAllowedPropertyNamesKey];
119 | }
120 |
121 | #pragma mark - 归档属性白名单配置
122 | + (void)mj_setupAllowedCodingPropertyNames:(MJAllowedCodingPropertyNames)allowedCodingPropertyNames
123 | {
124 | [self mj_setupBlockReturnValue:allowedCodingPropertyNames key:&MJAllowedCodingPropertyNamesKey];
125 | }
126 |
127 | + (NSMutableArray *)mj_totalAllowedCodingPropertyNames
128 | {
129 | return [self mj_totalObjectsWithSelector:@selector(mj_allowedCodingPropertyNames) key:&MJAllowedCodingPropertyNamesKey];
130 | }
131 | #pragma mark - block和方法处理:存储block的返回值
132 | + (void)mj_setupBlockReturnValue:(id (^)())block key:(const char *)key
133 | {
134 | if (block) {
135 | objc_setAssociatedObject(self, key, block(), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
136 | } else {
137 | objc_setAssociatedObject(self, key, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
138 | }
139 |
140 | // 清空数据
141 | [[self dictForKey:key] removeAllObjects];
142 | }
143 |
144 | + (NSMutableArray *)mj_totalObjectsWithSelector:(SEL)selector key:(const char *)key
145 | {
146 | NSMutableArray *array = [self dictForKey:key][NSStringFromClass(self)];
147 | if (array) return array;
148 |
149 | // 创建、存储
150 | [self dictForKey:key][NSStringFromClass(self)] = array = [NSMutableArray array];
151 |
152 | if ([self respondsToSelector:selector]) {
153 | #pragma clang diagnostic push
154 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
155 | NSArray *subArray = [self performSelector:selector];
156 | #pragma clang diagnostic pop
157 | if (subArray) {
158 | [array addObjectsFromArray:subArray];
159 | }
160 | }
161 |
162 | [self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
163 | NSArray *subArray = objc_getAssociatedObject(c, key);
164 | [array addObjectsFromArray:subArray];
165 | }];
166 | return array;
167 | }
168 | @end
169 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/MJExtension/NSObject+MJCoding.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+MJCoding.h
3 | // MJExtension
4 | //
5 | // Created by mj on 14-1-15.
6 | // Copyright (c) 2014年 小码哥. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "MJExtensionConst.h"
11 |
12 | /**
13 | * Codeing协议
14 | */
15 | @protocol MJCoding
16 | @optional
17 | /**
18 | * 这个数组中的属性名才会进行归档
19 | */
20 | + (NSArray *)mj_allowedCodingPropertyNames;
21 | /**
22 | * 这个数组中的属性名将会被忽略:不进行归档
23 | */
24 | + (NSArray *)mj_ignoredCodingPropertyNames;
25 | @end
26 |
27 | @interface NSObject (MJCoding)
28 | /**
29 | * 解码(从文件中解析对象)
30 | */
31 | - (void)mj_decode:(NSCoder *)decoder;
32 | /**
33 | * 编码(将对象写入文件中)
34 | */
35 | - (void)mj_encode:(NSCoder *)encoder;
36 | @end
37 |
38 | /**
39 | 归档的实现
40 | */
41 | #define MJCodingImplementation \
42 | - (id)initWithCoder:(NSCoder *)decoder \
43 | { \
44 | if (self = [super init]) { \
45 | [self mj_decode:decoder]; \
46 | } \
47 | return self; \
48 | } \
49 | \
50 | - (void)encodeWithCoder:(NSCoder *)encoder \
51 | { \
52 | [self mj_encode:encoder]; \
53 | }
54 |
55 | #define MJExtensionCodingImplementation MJCodingImplementation
--------------------------------------------------------------------------------
/ZFVoteViewDemo/MJExtension/NSObject+MJCoding.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+MJCoding.m
3 | // MJExtension
4 | //
5 | // Created by mj on 14-1-15.
6 | // Copyright (c) 2014年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "NSObject+MJCoding.h"
10 | #import "NSObject+MJClass.h"
11 | #import "NSObject+MJProperty.h"
12 | #import "MJProperty.h"
13 |
14 | @implementation NSObject (MJCoding)
15 |
16 | - (void)mj_encode:(NSCoder *)encoder
17 | {
18 | Class clazz = [self class];
19 |
20 | NSArray *allowedCodingPropertyNames = [clazz mj_totalAllowedCodingPropertyNames];
21 | NSArray *ignoredCodingPropertyNames = [clazz mj_totalIgnoredCodingPropertyNames];
22 |
23 | [clazz mj_enumerateProperties:^(MJProperty *property, BOOL *stop) {
24 | // 检测是否被忽略
25 | if (allowedCodingPropertyNames.count && ![allowedCodingPropertyNames containsObject:property.name]) return;
26 | if ([ignoredCodingPropertyNames containsObject:property.name]) return;
27 |
28 | id value = [property valueForObject:self];
29 | if (value == nil) return;
30 | [encoder encodeObject:value forKey:property.name];
31 | }];
32 | }
33 |
34 | - (void)mj_decode:(NSCoder *)decoder
35 | {
36 | Class clazz = [self class];
37 |
38 | NSArray *allowedCodingPropertyNames = [clazz mj_totalAllowedCodingPropertyNames];
39 | NSArray *ignoredCodingPropertyNames = [clazz mj_totalIgnoredCodingPropertyNames];
40 |
41 | [clazz mj_enumerateProperties:^(MJProperty *property, BOOL *stop) {
42 | // 检测是否被忽略
43 | if (allowedCodingPropertyNames.count && ![allowedCodingPropertyNames containsObject:property.name]) return;
44 | if ([ignoredCodingPropertyNames containsObject:property.name]) return;
45 |
46 | id value = [decoder decodeObjectForKey:property.name];
47 | if (value == nil) { // 兼容以前的MJExtension版本
48 | value = [decoder decodeObjectForKey:[@"_" stringByAppendingString:property.name]];
49 | }
50 | if (value == nil) return;
51 | [property setValue:value forObject:self];
52 | }];
53 | }
54 | @end
55 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/MJExtension/NSObject+MJKeyValue.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+MJKeyValue.h
3 | // MJExtension
4 | //
5 | // Created by mj on 13-8-24.
6 | // Copyright (c) 2013年 小码哥. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "MJExtensionConst.h"
11 | #import
12 | #import "MJProperty.h"
13 |
14 | /**
15 | * KeyValue协议
16 | */
17 | @protocol MJKeyValue
18 | @optional
19 | /**
20 | * 只有这个数组中的属性名才允许进行字典和模型的转换
21 | */
22 | + (NSArray *)mj_allowedPropertyNames;
23 |
24 | /**
25 | * 这个数组中的属性名将会被忽略:不进行字典和模型的转换
26 | */
27 | + (NSArray *)mj_ignoredPropertyNames;
28 |
29 | /**
30 | * 将属性名换为其他key去字典中取值
31 | *
32 | * @return 字典中的key是属性名,value是从字典中取值用的key
33 | */
34 | + (NSDictionary *)mj_replacedKeyFromPropertyName;
35 |
36 | /**
37 | * 将属性名换为其他key去字典中取值
38 | *
39 | * @return 从字典中取值用的key
40 | */
41 | + (id)mj_replacedKeyFromPropertyName121:(NSString *)propertyName;
42 |
43 | /**
44 | * 数组中需要转换的模型类
45 | *
46 | * @return 字典中的key是数组属性名,value是数组中存放模型的Class(Class类型或者NSString类型)
47 | */
48 | + (NSDictionary *)mj_objectClassInArray;
49 |
50 | /**
51 | * 旧值换新值,用于过滤字典中的值
52 | *
53 | * @param oldValue 旧值
54 | *
55 | * @return 新值
56 | */
57 | - (id)mj_newValueFromOldValue:(id)oldValue property:(MJProperty *)property;
58 |
59 | /**
60 | * 当字典转模型完毕时调用
61 | */
62 | - (void)mj_keyValuesDidFinishConvertingToObject;
63 |
64 | /**
65 | * 当模型转字典完毕时调用
66 | */
67 | - (void)mj_objectDidFinishConvertingToKeyValues;
68 | @end
69 |
70 | @interface NSObject (MJKeyValue)
71 | #pragma mark - 类方法
72 | /**
73 | * 字典转模型过程中遇到的错误
74 | */
75 | + (NSError *)mj_error;
76 |
77 | /**
78 | * 模型转字典时,字典的key是否参考replacedKeyFromPropertyName等方法(父类设置了,子类也会继承下来)
79 | */
80 | + (void)mj_referenceReplacedKeyWhenCreatingKeyValues:(BOOL)reference;
81 |
82 | #pragma mark - 对象方法
83 | /**
84 | * 将字典的键值对转成模型属性
85 | * @param keyValues 字典(可以是NSDictionary、NSData、NSString)
86 | */
87 | - (instancetype)mj_setKeyValues:(id)keyValues;
88 |
89 | /**
90 | * 将字典的键值对转成模型属性
91 | * @param keyValues 字典(可以是NSDictionary、NSData、NSString)
92 | * @param context CoreData上下文
93 | */
94 | - (instancetype)mj_setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context;
95 |
96 | /**
97 | * 将模型转成字典
98 | * @return 字典
99 | */
100 | - (NSMutableDictionary *)mj_keyValues;
101 | - (NSMutableDictionary *)mj_keyValuesWithKeys:(NSArray *)keys;
102 | - (NSMutableDictionary *)mj_keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys;
103 |
104 | /**
105 | * 通过模型数组来创建一个字典数组
106 | * @param objectArray 模型数组
107 | * @return 字典数组
108 | */
109 | + (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray;
110 | + (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys;
111 | + (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys;
112 |
113 | #pragma mark - 字典转模型
114 | /**
115 | * 通过字典来创建一个模型
116 | * @param keyValues 字典(可以是NSDictionary、NSData、NSString)
117 | * @return 新建的对象
118 | */
119 | + (instancetype)mj_objectWithKeyValues:(id)keyValues;
120 |
121 | /**
122 | * 通过字典来创建一个CoreData模型
123 | * @param keyValues 字典(可以是NSDictionary、NSData、NSString)
124 | * @param context CoreData上下文
125 | * @return 新建的对象
126 | */
127 | + (instancetype)mj_objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context;
128 |
129 | /**
130 | * 通过plist来创建一个模型
131 | * @param filename 文件名(仅限于mainBundle中的文件)
132 | * @return 新建的对象
133 | */
134 | + (instancetype)mj_objectWithFilename:(NSString *)filename;
135 |
136 | /**
137 | * 通过plist来创建一个模型
138 | * @param file 文件全路径
139 | * @return 新建的对象
140 | */
141 | + (instancetype)mj_objectWithFile:(NSString *)file;
142 |
143 | #pragma mark - 字典数组转模型数组
144 | /**
145 | * 通过字典数组来创建一个模型数组
146 | * @param keyValuesArray 字典数组(可以是NSDictionary、NSData、NSString)
147 | * @return 模型数组
148 | */
149 | + (NSMutableArray *)mj_objectArrayWithKeyValuesArray:(id)keyValuesArray;
150 |
151 | /**
152 | * 通过字典数组来创建一个模型数组
153 | * @param keyValuesArray 字典数组(可以是NSDictionary、NSData、NSString)
154 | * @param context CoreData上下文
155 | * @return 模型数组
156 | */
157 | + (NSMutableArray *)mj_objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context;
158 |
159 | /**
160 | * 通过plist来创建一个模型数组
161 | * @param filename 文件名(仅限于mainBundle中的文件)
162 | * @return 模型数组
163 | */
164 | + (NSMutableArray *)mj_objectArrayWithFilename:(NSString *)filename;
165 |
166 | /**
167 | * 通过plist来创建一个模型数组
168 | * @param file 文件全路径
169 | * @return 模型数组
170 | */
171 | + (NSMutableArray *)mj_objectArrayWithFile:(NSString *)file;
172 |
173 | #pragma mark - 转换为JSON
174 | /**
175 | * 转换为JSON Data
176 | */
177 | - (NSData *)mj_JSONData;
178 | /**
179 | * 转换为字典或者数组
180 | */
181 | - (id)mj_JSONObject;
182 | /**
183 | * 转换为JSON 字符串
184 | */
185 | - (NSString *)mj_JSONString;
186 | @end
187 |
188 | @interface NSObject (MJKeyValueDeprecated_v_2_5_16)
189 | - (instancetype)setKeyValues:(id)keyValue MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
190 | - (instancetype)setKeyValues:(id)keyValues error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
191 | - (instancetype)setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
192 | - (instancetype)setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
193 | + (void)referenceReplacedKeyWhenCreatingKeyValues:(BOOL)reference MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
194 | - (NSMutableDictionary *)keyValues MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
195 | - (NSMutableDictionary *)keyValuesWithError:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
196 | - (NSMutableDictionary *)keyValuesWithKeys:(NSArray *)keys MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
197 | - (NSMutableDictionary *)keyValuesWithKeys:(NSArray *)keys error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
198 | - (NSMutableDictionary *)keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
199 | - (NSMutableDictionary *)keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
200 | + (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
201 | + (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
202 | + (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
203 | + (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
204 | + (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
205 | + (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
206 | + (instancetype)objectWithKeyValues:(id)keyValues MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
207 | + (instancetype)objectWithKeyValues:(id)keyValues error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
208 | + (instancetype)objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
209 | + (instancetype)objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
210 | + (instancetype)objectWithFilename:(NSString *)filename MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
211 | + (instancetype)objectWithFilename:(NSString *)filename error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
212 | + (instancetype)objectWithFile:(NSString *)file MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
213 | + (instancetype)objectWithFile:(NSString *)file error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
214 | + (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
215 | + (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
216 | + (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
217 | + (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
218 | + (NSMutableArray *)objectArrayWithFilename:(NSString *)filename MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
219 | + (NSMutableArray *)objectArrayWithFilename:(NSString *)filename error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
220 | + (NSMutableArray *)objectArrayWithFile:(NSString *)file MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
221 | + (NSMutableArray *)objectArrayWithFile:(NSString *)file error:(NSError **)error MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
222 | - (NSData *)JSONData MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
223 | - (id)JSONObject MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
224 | - (NSString *)JSONString MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
225 | @end
226 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/MJExtension/NSObject+MJKeyValue.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+MJKeyValue.m
3 | // MJExtension
4 | //
5 | // Created by mj on 13-8-24.
6 | // Copyright (c) 2013年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "NSObject+MJKeyValue.h"
10 | #import "NSObject+MJProperty.h"
11 | #import "NSString+MJExtension.h"
12 | #import "MJProperty.h"
13 | #import "MJPropertyType.h"
14 | #import "MJExtensionConst.h"
15 | #import "MJFoundation.h"
16 | #import "NSString+MJExtension.h"
17 | #import "NSObject+MJClass.h"
18 |
19 | @implementation NSObject (MJKeyValue)
20 |
21 | #pragma mark - 错误
22 | static const char MJErrorKey = '\0';
23 | + (NSError *)mj_error
24 | {
25 | return objc_getAssociatedObject(self, &MJErrorKey);
26 | }
27 |
28 | + (void)setMj_error:(NSError *)error
29 | {
30 | objc_setAssociatedObject(self, &MJErrorKey, error, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
31 | }
32 |
33 | #pragma mark - 模型 -> 字典时的参考
34 | /** 模型转字典时,字典的key是否参考replacedKeyFromPropertyName等方法(父类设置了,子类也会继承下来) */
35 | static const char MJReferenceReplacedKeyWhenCreatingKeyValuesKey = '\0';
36 |
37 | + (void)mj_referenceReplacedKeyWhenCreatingKeyValues:(BOOL)reference
38 | {
39 | objc_setAssociatedObject(self, &MJReferenceReplacedKeyWhenCreatingKeyValuesKey, @(reference), OBJC_ASSOCIATION_ASSIGN);
40 | }
41 |
42 | + (BOOL)mj_isReferenceReplacedKeyWhenCreatingKeyValues
43 | {
44 | __block id value = objc_getAssociatedObject(self, &MJReferenceReplacedKeyWhenCreatingKeyValuesKey);
45 | if (!value) {
46 | [self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
47 | value = objc_getAssociatedObject(c, &MJReferenceReplacedKeyWhenCreatingKeyValuesKey);
48 |
49 | if (value) *stop = YES;
50 | }];
51 | }
52 | return [value boolValue];
53 | }
54 |
55 | #pragma mark - --常用的对象--
56 | static NSNumberFormatter *numberFormatter_;
57 | + (void)load
58 | {
59 | numberFormatter_ = [[NSNumberFormatter alloc] init];
60 |
61 | // 默认设置
62 | [self mj_referenceReplacedKeyWhenCreatingKeyValues:YES];
63 | }
64 |
65 | #pragma mark - --公共方法--
66 | #pragma mark - 字典 -> 模型
67 | - (instancetype)mj_setKeyValues:(id)keyValues
68 | {
69 | return [self mj_setKeyValues:keyValues context:nil];
70 | }
71 |
72 | /**
73 | 核心代码:
74 | */
75 | - (instancetype)mj_setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context
76 | {
77 | // 获得JSON对象
78 | keyValues = [keyValues mj_JSONObject];
79 |
80 | MJExtensionAssertError([keyValues isKindOfClass:[NSDictionary class]], self, [self class], @"keyValues参数不是一个字典");
81 |
82 | Class clazz = [self class];
83 | NSArray *allowedPropertyNames = [clazz mj_totalAllowedPropertyNames];
84 | NSArray *ignoredPropertyNames = [clazz mj_totalIgnoredPropertyNames];
85 |
86 | //通过封装的方法回调一个通过运行时编写的,用于返回属性列表的方法。
87 | [clazz mj_enumerateProperties:^(MJProperty *property, BOOL *stop) {
88 | @try {
89 | // 0.检测是否被忽略
90 | if (allowedPropertyNames.count && ![allowedPropertyNames containsObject:property.name]) return;
91 | if ([ignoredPropertyNames containsObject:property.name]) return;
92 |
93 | // 1.取出属性值
94 | id value;
95 | NSArray *propertyKeyses = [property propertyKeysForClass:clazz];
96 | for (NSArray *propertyKeys in propertyKeyses) {
97 | value = keyValues;
98 | for (MJPropertyKey *propertyKey in propertyKeys) {
99 | value = [propertyKey valueInObject:value];
100 | }
101 | if (value) break;
102 | }
103 |
104 | // 值的过滤
105 | id newValue = [clazz mj_getNewValueFromObject:self oldValue:value property:property];
106 | if (newValue != value) { // 有过滤后的新值
107 | [property setValue:newValue forObject:self];
108 | return;
109 | }
110 |
111 | // 如果没有值,就直接返回
112 | if (!value || value == [NSNull null]) return;
113 |
114 | // 2.复杂处理
115 | MJPropertyType *type = property.type;
116 | Class propertyClass = type.typeClass;
117 | Class objectClass = [property objectClassInArrayForClass:[self class]];
118 |
119 | // 不可变 -> 可变处理
120 | if (propertyClass == [NSMutableArray class] && [value isKindOfClass:[NSArray class]]) {
121 | value = [NSMutableArray arrayWithArray:value];
122 | } else if (propertyClass == [NSMutableDictionary class] && [value isKindOfClass:[NSDictionary class]]) {
123 | value = [NSMutableDictionary dictionaryWithDictionary:value];
124 | } else if (propertyClass == [NSMutableString class] && [value isKindOfClass:[NSString class]]) {
125 | value = [NSMutableString stringWithString:value];
126 | } else if (propertyClass == [NSMutableData class] && [value isKindOfClass:[NSData class]]) {
127 | value = [NSMutableData dataWithData:value];
128 | }
129 |
130 | if (!type.isFromFoundation && propertyClass) { // 模型属性
131 | value = [propertyClass mj_objectWithKeyValues:value context:context];
132 | } else if (objectClass) {
133 | if (objectClass == [NSURL class] && [value isKindOfClass:[NSArray class]]) {
134 | // string array -> url array
135 | NSMutableArray *urlArray = [NSMutableArray array];
136 | for (NSString *string in value) {
137 | if (![string isKindOfClass:[NSString class]]) continue;
138 | [urlArray addObject:string.mj_url];
139 | }
140 | value = urlArray;
141 | } else { // 字典数组-->模型数组
142 | value = [objectClass mj_objectArrayWithKeyValuesArray:value context:context];
143 | }
144 | } else {
145 | if (propertyClass == [NSString class]) {
146 | if ([value isKindOfClass:[NSNumber class]]) {
147 | // NSNumber -> NSString
148 | value = [value description];
149 | } else if ([value isKindOfClass:[NSURL class]]) {
150 | // NSURL -> NSString
151 | value = [value absoluteString];
152 | }
153 | } else if ([value isKindOfClass:[NSString class]]) {
154 | if (propertyClass == [NSURL class]) {
155 | // NSString -> NSURL
156 | // 字符串转码
157 | value = [value mj_url];
158 | } else if (type.isNumberType) {
159 | NSString *oldValue = value;
160 |
161 | // NSString -> NSNumber
162 | if (type.typeClass == [NSDecimalNumber class]) {
163 | value = [NSDecimalNumber decimalNumberWithString:oldValue];
164 | } else {
165 | value = [numberFormatter_ numberFromString:oldValue];
166 | }
167 |
168 | // 如果是BOOL
169 | if (type.isBoolType) {
170 | // 字符串转BOOL(字符串没有charValue方法)
171 | // 系统会调用字符串的charValue转为BOOL类型
172 | NSString *lower = [oldValue lowercaseString];
173 | if ([lower isEqualToString:@"yes"] || [lower isEqualToString:@"true"]) {
174 | value = @YES;
175 | } else if ([lower isEqualToString:@"no"] || [lower isEqualToString:@"false"]) {
176 | value = @NO;
177 | }
178 | }
179 | }
180 | }
181 |
182 | // value和property类型不匹配
183 | if (propertyClass && ![value isKindOfClass:propertyClass]) {
184 | value = nil;
185 | }
186 | }
187 |
188 | // 3.赋值
189 | [property setValue:value forObject:self];
190 | } @catch (NSException *exception) {
191 | MJExtensionBuildError([self class], exception.reason);
192 | MJExtensionLog(@"%@", exception);
193 | }
194 | }];
195 |
196 | // 转换完毕
197 | if ([self respondsToSelector:@selector(mj_keyValuesDidFinishConvertingToObject)]) {
198 | [self mj_keyValuesDidFinishConvertingToObject];
199 | }
200 | return self;
201 | }
202 |
203 | + (instancetype)mj_objectWithKeyValues:(id)keyValues
204 | {
205 | return [self mj_objectWithKeyValues:keyValues context:nil];
206 | }
207 |
208 | + (instancetype)mj_objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context
209 | {
210 | // 获得JSON对象
211 | keyValues = [keyValues mj_JSONObject];
212 | MJExtensionAssertError([keyValues isKindOfClass:[NSDictionary class]], nil, [self class], @"keyValues参数不是一个字典");
213 |
214 | if ([self isSubclassOfClass:[NSManagedObject class]] && context) {
215 | return [[NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass(self) inManagedObjectContext:context] mj_setKeyValues:keyValues context:context];
216 | }
217 | return [[[self alloc] init] mj_setKeyValues:keyValues];
218 | }
219 |
220 | + (instancetype)mj_objectWithFilename:(NSString *)filename
221 | {
222 | MJExtensionAssertError(filename != nil, nil, [self class], @"filename参数为nil");
223 |
224 | return [self mj_objectWithFile:[[NSBundle mainBundle] pathForResource:filename ofType:nil]];
225 | }
226 |
227 | + (instancetype)mj_objectWithFile:(NSString *)file
228 | {
229 | MJExtensionAssertError(file != nil, nil, [self class], @"file参数为nil");
230 |
231 | return [self mj_objectWithKeyValues:[NSDictionary dictionaryWithContentsOfFile:file]];
232 | }
233 |
234 | #pragma mark - 字典数组 -> 模型数组
235 | + (NSMutableArray *)mj_objectArrayWithKeyValuesArray:(NSArray *)keyValuesArray
236 | {
237 | return [self mj_objectArrayWithKeyValuesArray:keyValuesArray context:nil];
238 | }
239 |
240 | + (NSMutableArray *)mj_objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context
241 | {
242 | // 如果是JSON字符串
243 | keyValuesArray = [keyValuesArray mj_JSONObject];
244 |
245 | // 1.判断真实性
246 | MJExtensionAssertError([keyValuesArray isKindOfClass:[NSArray class]], nil, [self class], @"keyValuesArray参数不是一个数组");
247 |
248 | // 如果数组里面放的是NSString、NSNumber等数据
249 | if ([MJFoundation isClassFromFoundation:self]) return [NSMutableArray arrayWithArray:keyValuesArray];
250 |
251 |
252 | // 2.创建数组
253 | NSMutableArray *modelArray = [NSMutableArray array];
254 |
255 | // 3.遍历
256 | for (NSDictionary *keyValues in keyValuesArray) {
257 | if ([keyValues isKindOfClass:[NSArray class]]){
258 | [modelArray addObject:[self mj_objectArrayWithKeyValuesArray:keyValues context:context]];
259 | } else {
260 | id model = [self mj_objectWithKeyValues:keyValues context:context];
261 | if (model) [modelArray addObject:model];
262 | }
263 | }
264 |
265 | return modelArray;
266 | }
267 |
268 | + (NSMutableArray *)mj_objectArrayWithFilename:(NSString *)filename
269 | {
270 | MJExtensionAssertError(filename != nil, nil, [self class], @"filename参数为nil");
271 |
272 | return [self mj_objectArrayWithFile:[[NSBundle mainBundle] pathForResource:filename ofType:nil]];
273 | }
274 |
275 | + (NSMutableArray *)mj_objectArrayWithFile:(NSString *)file
276 | {
277 | MJExtensionAssertError(file != nil, nil, [self class], @"file参数为nil");
278 |
279 | return [self mj_objectArrayWithKeyValuesArray:[NSArray arrayWithContentsOfFile:file]];
280 | }
281 |
282 | #pragma mark - 模型 -> 字典
283 | - (NSMutableDictionary *)mj_keyValues
284 | {
285 | return [self mj_keyValuesWithKeys:nil ignoredKeys:nil];
286 | }
287 |
288 | - (NSMutableDictionary *)mj_keyValuesWithKeys:(NSArray *)keys
289 | {
290 | return [self mj_keyValuesWithKeys:keys ignoredKeys:nil];
291 | }
292 |
293 | - (NSMutableDictionary *)mj_keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys
294 | {
295 | return [self mj_keyValuesWithKeys:nil ignoredKeys:ignoredKeys];
296 | }
297 |
298 | - (NSMutableDictionary *)mj_keyValuesWithKeys:(NSArray *)keys ignoredKeys:(NSArray *)ignoredKeys
299 | {
300 | // 如果自己不是模型类, 那就返回自己
301 | MJExtensionAssertError(![MJFoundation isClassFromFoundation:[self class]], (NSMutableDictionary *)self, [self class], @"不是自定义的模型类")
302 |
303 | id keyValues = [NSMutableDictionary dictionary];
304 |
305 | Class clazz = [self class];
306 | NSArray *allowedPropertyNames = [clazz mj_totalAllowedPropertyNames];
307 | NSArray *ignoredPropertyNames = [clazz mj_totalIgnoredPropertyNames];
308 |
309 | [clazz mj_enumerateProperties:^(MJProperty *property, BOOL *stop) {
310 | @try {
311 | // 0.检测是否被忽略
312 | if (allowedPropertyNames.count && ![allowedPropertyNames containsObject:property.name]) return;
313 | if ([ignoredPropertyNames containsObject:property.name]) return;
314 | if (keys.count && ![keys containsObject:property.name]) return;
315 | if ([ignoredKeys containsObject:property.name]) return;
316 |
317 | // 1.取出属性值
318 | id value = [property valueForObject:self];
319 | if (!value) return;
320 |
321 | // 2.如果是模型属性
322 | MJPropertyType *type = property.type;
323 | Class propertyClass = type.typeClass;
324 | if (!type.isFromFoundation && propertyClass) {
325 | value = [value mj_keyValues];
326 | } else if ([value isKindOfClass:[NSArray class]]) {
327 | // 3.处理数组里面有模型的情况
328 | value = [NSObject mj_keyValuesArrayWithObjectArray:value];
329 | } else if (propertyClass == [NSURL class]) {
330 | value = [value absoluteString];
331 | }
332 |
333 | // 4.赋值
334 | if ([clazz mj_isReferenceReplacedKeyWhenCreatingKeyValues]) {
335 | NSArray *propertyKeys = [[property propertyKeysForClass:clazz] firstObject];
336 | NSUInteger keyCount = propertyKeys.count;
337 | // 创建字典
338 | __block id innerContainer = keyValues;
339 | [propertyKeys enumerateObjectsUsingBlock:^(MJPropertyKey *propertyKey, NSUInteger idx, BOOL *stop) {
340 | // 下一个属性
341 | MJPropertyKey *nextPropertyKey = nil;
342 | if (idx != keyCount - 1) {
343 | nextPropertyKey = propertyKeys[idx + 1];
344 | }
345 |
346 | if (nextPropertyKey) { // 不是最后一个key
347 | // 当前propertyKey对应的字典或者数组
348 | id tempInnerContainer = [propertyKey valueInObject:innerContainer];
349 | if (tempInnerContainer == nil || [tempInnerContainer isKindOfClass:[NSNull class]]) {
350 | if (nextPropertyKey.type == MJPropertyKeyTypeDictionary) {
351 | tempInnerContainer = [NSMutableDictionary dictionary];
352 | } else {
353 | tempInnerContainer = [NSMutableArray array];
354 | }
355 | if (propertyKey.type == MJPropertyKeyTypeDictionary) {
356 | innerContainer[propertyKey.name] = tempInnerContainer;
357 | } else {
358 | innerContainer[propertyKey.name.intValue] = tempInnerContainer;
359 | }
360 | }
361 |
362 | if ([tempInnerContainer isKindOfClass:[NSMutableArray class]]) {
363 | NSMutableArray *tempInnerContainerArray = tempInnerContainer;
364 | int index = nextPropertyKey.name.intValue;
365 | while (tempInnerContainerArray.count < index + 1) {
366 | [tempInnerContainerArray addObject:[NSNull null]];
367 | }
368 | }
369 |
370 | innerContainer = tempInnerContainer;
371 | } else { // 最后一个key
372 | if (propertyKey.type == MJPropertyKeyTypeDictionary) {
373 | innerContainer[propertyKey.name] = value;
374 | } else {
375 | innerContainer[propertyKey.name.intValue] = value;
376 | }
377 | }
378 | }];
379 | } else {
380 | keyValues[property.name] = value;
381 | }
382 | } @catch (NSException *exception) {
383 | MJExtensionBuildError([self class], exception.reason);
384 | MJExtensionLog(@"%@", exception);
385 | }
386 | }];
387 |
388 | // 转换完毕
389 | if ([self respondsToSelector:@selector(mj_objectDidFinishConvertingToKeyValues)]) {
390 | [self mj_objectDidFinishConvertingToKeyValues];
391 | }
392 |
393 | return keyValues;
394 | }
395 | #pragma mark - 模型数组 -> 字典数组
396 | + (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray
397 | {
398 | return [self mj_keyValuesArrayWithObjectArray:objectArray keys:nil ignoredKeys:nil];
399 | }
400 |
401 | + (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys
402 | {
403 | return [self mj_keyValuesArrayWithObjectArray:objectArray keys:keys ignoredKeys:nil];
404 | }
405 |
406 | + (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys
407 | {
408 | return [self mj_keyValuesArrayWithObjectArray:objectArray keys:nil ignoredKeys:ignoredKeys];
409 | }
410 |
411 | + (NSMutableArray *)mj_keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys ignoredKeys:(NSArray *)ignoredKeys
412 | {
413 | // 0.判断真实性
414 | MJExtensionAssertError([objectArray isKindOfClass:[NSArray class]], nil, [self class], @"objectArray参数不是一个数组");
415 |
416 | // 1.创建数组
417 | NSMutableArray *keyValuesArray = [NSMutableArray array];
418 | for (id object in objectArray) {
419 | if (keys) {
420 | [keyValuesArray addObject:[object mj_keyValuesWithKeys:keys]];
421 | } else {
422 | [keyValuesArray addObject:[object mj_keyValuesWithIgnoredKeys:ignoredKeys]];
423 | }
424 | }
425 | return keyValuesArray;
426 | }
427 |
428 | #pragma mark - 转换为JSON
429 | - (NSData *)mj_JSONData
430 | {
431 | if ([self isKindOfClass:[NSString class]]) {
432 | return [((NSString *)self) dataUsingEncoding:NSUTF8StringEncoding];
433 | } else if ([self isKindOfClass:[NSData class]]) {
434 | return (NSData *)self;
435 | }
436 |
437 | return [NSJSONSerialization dataWithJSONObject:[self mj_JSONObject] options:kNilOptions error:nil];
438 | }
439 |
440 | - (id)mj_JSONObject
441 | {
442 | if ([self isKindOfClass:[NSString class]]) {
443 | return [NSJSONSerialization JSONObjectWithData:[((NSString *)self) dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil];
444 | } else if ([self isKindOfClass:[NSData class]]) {
445 | return [NSJSONSerialization JSONObjectWithData:(NSData *)self options:kNilOptions error:nil];
446 | }
447 |
448 | return self.mj_keyValues;
449 | }
450 |
451 | - (NSString *)mj_JSONString
452 | {
453 | if ([self isKindOfClass:[NSString class]]) {
454 | return (NSString *)self;
455 | } else if ([self isKindOfClass:[NSData class]]) {
456 | return [[NSString alloc] initWithData:(NSData *)self encoding:NSUTF8StringEncoding];
457 | }
458 |
459 | return [[NSString alloc] initWithData:[self mj_JSONData] encoding:NSUTF8StringEncoding];
460 | }
461 | @end
462 |
463 | @implementation NSObject (MJKeyValueDeprecated_v_2_5_16)
464 | - (instancetype)setKeyValues:(id)keyValues
465 | {
466 | return [self mj_setKeyValues:keyValues];
467 | }
468 |
469 | - (instancetype)setKeyValues:(id)keyValues error:(NSError **)error
470 | {
471 | id value = [self mj_setKeyValues:keyValues];
472 | if (error != NULL) {
473 | *error = [self.class mj_error];
474 | }
475 | return value;
476 |
477 | }
478 |
479 | - (instancetype)setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context
480 | {
481 | return [self mj_setKeyValues:keyValues context:context];
482 | }
483 |
484 | - (instancetype)setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context error:(NSError **)error
485 | {
486 | id value = [self mj_setKeyValues:keyValues context:context];
487 | if (error != NULL) {
488 | *error = [self.class mj_error];
489 | }
490 | return value;
491 | }
492 |
493 | + (void)referenceReplacedKeyWhenCreatingKeyValues:(BOOL)reference
494 | {
495 | [self mj_referenceReplacedKeyWhenCreatingKeyValues:reference];
496 | }
497 |
498 | - (NSMutableDictionary *)keyValues
499 | {
500 | return [self mj_keyValues];
501 | }
502 |
503 | - (NSMutableDictionary *)keyValuesWithError:(NSError **)error
504 | {
505 | id value = [self mj_keyValues];
506 | if (error != NULL) {
507 | *error = [self.class mj_error];
508 | }
509 | return value;
510 | }
511 |
512 | - (NSMutableDictionary *)keyValuesWithKeys:(NSArray *)keys
513 | {
514 | return [self mj_keyValuesWithKeys:keys];
515 | }
516 |
517 | - (NSMutableDictionary *)keyValuesWithKeys:(NSArray *)keys error:(NSError **)error
518 | {
519 | id value = [self mj_keyValuesWithKeys:keys];
520 | if (error != NULL) {
521 | *error = [self.class mj_error];
522 | }
523 | return value;
524 | }
525 |
526 | - (NSMutableDictionary *)keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys
527 | {
528 | return [self mj_keyValuesWithIgnoredKeys:ignoredKeys];
529 | }
530 |
531 | - (NSMutableDictionary *)keyValuesWithIgnoredKeys:(NSArray *)ignoredKeys error:(NSError **)error
532 | {
533 | id value = [self mj_keyValuesWithIgnoredKeys:ignoredKeys];
534 | if (error != NULL) {
535 | *error = [self.class mj_error];
536 | }
537 | return value;
538 | }
539 |
540 | + (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray
541 | {
542 | return [self mj_keyValuesArrayWithObjectArray:objectArray];
543 | }
544 |
545 | + (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray error:(NSError **)error
546 | {
547 | id value = [self mj_keyValuesArrayWithObjectArray:objectArray];
548 | if (error != NULL) {
549 | *error = [self mj_error];
550 | }
551 | return value;
552 | }
553 |
554 | + (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys
555 | {
556 | return [self mj_keyValuesArrayWithObjectArray:objectArray keys:keys];
557 | }
558 |
559 | + (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray keys:(NSArray *)keys error:(NSError **)error
560 | {
561 | id value = [self mj_keyValuesArrayWithObjectArray:objectArray keys:keys];
562 | if (error != NULL) {
563 | *error = [self mj_error];
564 | }
565 | return value;
566 | }
567 |
568 | + (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys
569 | {
570 | return [self mj_keyValuesArrayWithObjectArray:objectArray ignoredKeys:ignoredKeys];
571 | }
572 |
573 | + (NSMutableArray *)keyValuesArrayWithObjectArray:(NSArray *)objectArray ignoredKeys:(NSArray *)ignoredKeys error:(NSError **)error
574 | {
575 | id value = [self mj_keyValuesArrayWithObjectArray:objectArray ignoredKeys:ignoredKeys];
576 | if (error != NULL) {
577 | *error = [self mj_error];
578 | }
579 | return value;
580 | }
581 |
582 | + (instancetype)objectWithKeyValues:(id)keyValues
583 | {
584 | return [self mj_objectWithKeyValues:keyValues];
585 | }
586 |
587 | + (instancetype)objectWithKeyValues:(id)keyValues error:(NSError **)error
588 | {
589 | id value = [self mj_objectWithKeyValues:keyValues];
590 | if (error != NULL) {
591 | *error = [self mj_error];
592 | }
593 | return value;
594 | }
595 |
596 | + (instancetype)objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context
597 | {
598 | return [self mj_objectWithKeyValues:keyValues context:context];
599 | }
600 |
601 | + (instancetype)objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context error:(NSError **)error
602 | {
603 | id value = [self mj_objectWithKeyValues:keyValues context:context];
604 | if (error != NULL) {
605 | *error = [self mj_error];
606 | }
607 | return value;
608 | }
609 |
610 | + (instancetype)objectWithFilename:(NSString *)filename
611 | {
612 | return [self mj_objectWithFilename:filename];
613 | }
614 |
615 | + (instancetype)objectWithFilename:(NSString *)filename error:(NSError **)error
616 | {
617 | id value = [self mj_objectWithFilename:filename];
618 | if (error != NULL) {
619 | *error = [self mj_error];
620 | }
621 | return value;
622 | }
623 |
624 | + (instancetype)objectWithFile:(NSString *)file
625 | {
626 | return [self mj_objectWithFile:file];
627 | }
628 |
629 | + (instancetype)objectWithFile:(NSString *)file error:(NSError **)error
630 | {
631 | id value = [self mj_objectWithFile:file];
632 | if (error != NULL) {
633 | *error = [self mj_error];
634 | }
635 | return value;
636 | }
637 |
638 | + (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray
639 | {
640 | return [self mj_objectArrayWithKeyValuesArray:keyValuesArray];
641 | }
642 |
643 | + (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray error:(NSError **)error
644 | {
645 | id value = [self mj_objectArrayWithKeyValuesArray:keyValuesArray];
646 | if (error != NULL) {
647 | *error = [self mj_error];
648 | }
649 | return value;
650 | }
651 |
652 | + (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context
653 | {
654 | return [self mj_objectArrayWithKeyValuesArray:keyValuesArray context:context];
655 | }
656 |
657 | + (NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray context:(NSManagedObjectContext *)context error:(NSError **)error
658 | {
659 | id value = [self mj_objectArrayWithKeyValuesArray:keyValuesArray context:context];
660 | if (error != NULL) {
661 | *error = [self mj_error];
662 | }
663 | return value;
664 | }
665 |
666 | + (NSMutableArray *)objectArrayWithFilename:(NSString *)filename
667 | {
668 | return [self mj_objectArrayWithFilename:filename];
669 | }
670 |
671 | + (NSMutableArray *)objectArrayWithFilename:(NSString *)filename error:(NSError **)error
672 | {
673 | id value = [self mj_objectArrayWithFilename:filename];
674 | if (error != NULL) {
675 | *error = [self mj_error];
676 | }
677 | return value;
678 | }
679 |
680 | + (NSMutableArray *)objectArrayWithFile:(NSString *)file
681 | {
682 | return [self mj_objectArrayWithFile:file];
683 | }
684 |
685 | + (NSMutableArray *)objectArrayWithFile:(NSString *)file error:(NSError **)error
686 | {
687 | id value = [self mj_objectArrayWithFile:file];
688 | if (error != NULL) {
689 | *error = [self mj_error];
690 | }
691 | return value;
692 | }
693 |
694 | - (NSData *)JSONData
695 | {
696 | return [self mj_JSONData];
697 | }
698 |
699 | - (id)JSONObject
700 | {
701 | return [self mj_JSONObject];
702 | }
703 |
704 | - (NSString *)JSONString
705 | {
706 | return [self mj_JSONString];
707 | }
708 | @end
--------------------------------------------------------------------------------
/ZFVoteViewDemo/MJExtension/NSObject+MJProperty.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+MJProperty.h
3 | // MJExtensionExample
4 | //
5 | // Created by MJ Lee on 15/4/17.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "MJExtensionConst.h"
11 |
12 | @class MJProperty;
13 |
14 | /**
15 | * 遍历成员变量用的block
16 | *
17 | * @param property 成员的包装对象
18 | * @param stop YES代表停止遍历,NO代表继续遍历
19 | */
20 | typedef void (^MJPropertiesEnumeration)(MJProperty *property, BOOL *stop);
21 |
22 | /** 将属性名换为其他key去字典中取值 */
23 | typedef NSDictionary * (^MJReplacedKeyFromPropertyName)();
24 | typedef id (^MJReplacedKeyFromPropertyName121)(NSString *propertyName);
25 | /** 数组中需要转换的模型类 */
26 | typedef NSDictionary * (^MJObjectClassInArray)();
27 | /** 用于过滤字典中的值 */
28 | typedef id (^MJNewValueFromOldValue)(id object, id oldValue, MJProperty *property);
29 |
30 | /**
31 | * 成员属性相关的扩展
32 | */
33 | @interface NSObject (MJProperty)
34 | #pragma mark - 遍历
35 | /**
36 | * 遍历所有的成员
37 | */
38 | + (void)mj_enumerateProperties:(MJPropertiesEnumeration)enumeration;
39 |
40 | #pragma mark - 新值配置
41 | /**
42 | * 用于过滤字典中的值
43 | *
44 | * @param newValueFormOldValue 用于过滤字典中的值
45 | */
46 | + (void)mj_setupNewValueFromOldValue:(MJNewValueFromOldValue)newValueFormOldValue;
47 | + (id)mj_getNewValueFromObject:(__unsafe_unretained id)object oldValue:(__unsafe_unretained id)oldValue property:(__unsafe_unretained MJProperty *)property;
48 |
49 | #pragma mark - key配置
50 | /**
51 | * 将属性名换为其他key去字典中取值
52 | *
53 | * @param replacedKeyFromPropertyName 将属性名换为其他key去字典中取值
54 | */
55 | + (void)mj_setupReplacedKeyFromPropertyName:(MJReplacedKeyFromPropertyName)replacedKeyFromPropertyName;
56 | /**
57 | * 将属性名换为其他key去字典中取值
58 | *
59 | * @param replacedKeyFromPropertyName121 将属性名换为其他key去字典中取值
60 | */
61 | + (void)mj_setupReplacedKeyFromPropertyName121:(MJReplacedKeyFromPropertyName121)replacedKeyFromPropertyName121;
62 |
63 | #pragma mark - array model class配置
64 | /**
65 | * 数组中需要转换的模型类
66 | *
67 | * @param objectClassInArray 数组中需要转换的模型类
68 | */
69 | + (void)mj_setupObjectClassInArray:(MJObjectClassInArray)objectClassInArray;
70 | @end
71 |
72 | @interface NSObject (MJPropertyDeprecated_v_2_5_16)
73 | + (void)enumerateProperties:(MJPropertiesEnumeration)enumeration MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
74 | + (void)setupNewValueFromOldValue:(MJNewValueFromOldValue)newValueFormOldValue MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
75 | + (id)getNewValueFromObject:(__unsafe_unretained id)object oldValue:(__unsafe_unretained id)oldValue property:(__unsafe_unretained MJProperty *)property MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
76 | + (void)setupReplacedKeyFromPropertyName:(MJReplacedKeyFromPropertyName)replacedKeyFromPropertyName MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
77 | + (void)setupReplacedKeyFromPropertyName121:(MJReplacedKeyFromPropertyName121)replacedKeyFromPropertyName121 MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
78 | + (void)setupObjectClassInArray:(MJObjectClassInArray)objectClassInArray MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
79 | @end
--------------------------------------------------------------------------------
/ZFVoteViewDemo/MJExtension/NSObject+MJProperty.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+MJProperty.m
3 | // MJExtensionExample
4 | //
5 | // Created by MJ Lee on 15/4/17.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "NSObject+MJProperty.h"
10 | #import "NSObject+MJKeyValue.h"
11 | #import "NSObject+MJCoding.h"
12 | #import "NSObject+MJClass.h"
13 | #import "MJProperty.h"
14 | #import "MJFoundation.h"
15 | #import
16 |
17 | #pragma clang diagnostic push
18 | #pragma clang diagnostic ignored "-Wundeclared-selector"
19 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
20 |
21 | static const char MJReplacedKeyFromPropertyNameKey = '\0';
22 | static const char MJReplacedKeyFromPropertyName121Key = '\0';
23 | static const char MJNewValueFromOldValueKey = '\0';
24 | static const char MJObjectClassInArrayKey = '\0';
25 |
26 | static const char MJCachedPropertiesKey = '\0';
27 |
28 | @implementation NSObject (Property)
29 |
30 | static NSMutableDictionary *replacedKeyFromPropertyNameDict_;
31 | static NSMutableDictionary *replacedKeyFromPropertyName121Dict_;
32 | static NSMutableDictionary *newValueFromOldValueDict_;
33 | static NSMutableDictionary *objectClassInArrayDict_;
34 | static NSMutableDictionary *cachedPropertiesDict_;
35 |
36 | + (void)load
37 | {
38 | replacedKeyFromPropertyNameDict_ = [NSMutableDictionary dictionary];
39 | replacedKeyFromPropertyName121Dict_ = [NSMutableDictionary dictionary];
40 | newValueFromOldValueDict_ = [NSMutableDictionary dictionary];
41 | objectClassInArrayDict_ = [NSMutableDictionary dictionary];
42 | cachedPropertiesDict_ = [NSMutableDictionary dictionary];
43 | }
44 |
45 | + (NSMutableDictionary *)dictForKey:(const void *)key
46 | {
47 | if (key == &MJReplacedKeyFromPropertyNameKey) return replacedKeyFromPropertyNameDict_;
48 | if (key == &MJReplacedKeyFromPropertyName121Key) return replacedKeyFromPropertyName121Dict_;
49 | if (key == &MJNewValueFromOldValueKey) return newValueFromOldValueDict_;
50 | if (key == &MJObjectClassInArrayKey) return objectClassInArrayDict_;
51 | if (key == &MJCachedPropertiesKey) return cachedPropertiesDict_;
52 | return nil;
53 | }
54 |
55 | #pragma mark - --私有方法--
56 | + (id)propertyKey:(NSString *)propertyName
57 | {
58 | MJExtensionAssertParamNotNil2(propertyName, nil);
59 |
60 | __block id key = nil;
61 | // 查看有没有需要替换的key
62 | if ([self respondsToSelector:@selector(mj_replacedKeyFromPropertyName121:)]) {
63 | key = [self mj_replacedKeyFromPropertyName121:propertyName];
64 | }
65 | // 兼容旧版本
66 | if ([self respondsToSelector:@selector(replacedKeyFromPropertyName121:)]) {
67 | key = [self performSelector:@selector(replacedKeyFromPropertyName121) withObject:propertyName];
68 | }
69 |
70 | // 调用block
71 | if (!key) {
72 | [self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
73 | MJReplacedKeyFromPropertyName121 block = objc_getAssociatedObject(c, &MJReplacedKeyFromPropertyName121Key);
74 | if (block) {
75 | key = block(propertyName);
76 | }
77 | if (key) *stop = YES;
78 | }];
79 | }
80 |
81 | // 查看有没有需要替换的key
82 | if ((!key || [key isEqual:propertyName]) && [self respondsToSelector:@selector(mj_replacedKeyFromPropertyName)]) {
83 | key = [self mj_replacedKeyFromPropertyName][propertyName];
84 | }
85 | // 兼容旧版本
86 | if ((!key || [key isEqual:propertyName]) && [self respondsToSelector:@selector(replacedKeyFromPropertyName)]) {
87 | key = [self performSelector:@selector(replacedKeyFromPropertyName)][propertyName];
88 | }
89 |
90 | if (!key || [key isEqual:propertyName]) {
91 | [self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
92 | NSDictionary *dict = objc_getAssociatedObject(c, &MJReplacedKeyFromPropertyNameKey);
93 | if (dict) {
94 | key = dict[propertyName];
95 | }
96 | if (key && ![key isEqual:propertyName]) *stop = YES;
97 | }];
98 | }
99 |
100 | // 2.用属性名作为key
101 | if (!key) key = propertyName;
102 |
103 | return key;
104 | }
105 |
106 | + (Class)propertyObjectClassInArray:(NSString *)propertyName
107 | {
108 | __block id clazz = nil;
109 | if ([self respondsToSelector:@selector(mj_objectClassInArray)]) {
110 | clazz = [self mj_objectClassInArray][propertyName];
111 | }
112 | // 兼容旧版本
113 | if ([self respondsToSelector:@selector(objectClassInArray)]) {
114 | clazz = [self performSelector:@selector(objectClassInArray)][propertyName];
115 | }
116 |
117 | if (!clazz) {
118 | [self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
119 | NSDictionary *dict = objc_getAssociatedObject(c, &MJObjectClassInArrayKey);
120 | if (dict) {
121 | clazz = dict[propertyName];
122 | }
123 | if (clazz) *stop = YES;
124 | }];
125 | }
126 |
127 | // 如果是NSString类型
128 | if ([clazz isKindOfClass:[NSString class]]) {
129 | clazz = NSClassFromString(clazz);
130 | }
131 | return clazz;
132 | }
133 |
134 | #pragma mark - --公共方法--
135 | + (void)mj_enumerateProperties:(MJPropertiesEnumeration)enumeration
136 | {
137 | // 获得成员变量
138 | NSArray *cachedProperties = [self properties];
139 |
140 | // 遍历成员变量
141 | BOOL stop = NO;
142 | for (MJProperty *property in cachedProperties) {
143 | enumeration(property, &stop);
144 | if (stop) break;
145 | }
146 | }
147 |
148 | #pragma mark - 公共方法
149 | + (NSMutableArray *)properties
150 | {
151 | NSMutableArray *cachedProperties = [self dictForKey:&MJCachedPropertiesKey][NSStringFromClass(self)];
152 |
153 | if (cachedProperties == nil) {
154 | cachedProperties = [NSMutableArray array];
155 |
156 | [self mj_enumerateClasses:^(__unsafe_unretained Class c, BOOL *stop) {
157 | // 1.获得所有的成员变量
158 | unsigned int outCount = 0;
159 | objc_property_t *properties = class_copyPropertyList(c, &outCount);
160 |
161 | // 2.遍历每一个成员变量
162 | for (unsigned int i = 0; i
10 | #import "MJExtensionConst.h"
11 |
12 | @interface NSString (MJExtension)
13 | /**
14 | * 驼峰转下划线(loveYou -> love_you)
15 | */
16 | - (NSString *)mj_underlineFromCamel;
17 | /**
18 | * 下划线转驼峰(love_you -> loveYou)
19 | */
20 | - (NSString *)mj_camelFromUnderline;
21 | /**
22 | * 首字母变大写
23 | */
24 | - (NSString *)mj_firstCharUpper;
25 | /**
26 | * 首字母变小写
27 | */
28 | - (NSString *)mj_firstCharLower;
29 |
30 | - (BOOL)mj_isPureInt;
31 |
32 | - (NSURL *)mj_url;
33 | @end
34 |
35 | @interface NSString (MJExtensionDeprecated_v_2_5_16)
36 | - (NSString *)underlineFromCamel MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
37 | - (NSString *)camelFromUnderline MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
38 | - (NSString *)firstCharUpper MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
39 | - (NSString *)firstCharLower MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
40 | - (BOOL)isPureInt MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
41 | - (NSURL *)url MJExtensionDeprecated("请在方法名前面加上mj_前缀,使用mj_***");
42 | @end
43 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/MJExtension/NSString+MJExtension.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSString+MJExtension.m
3 | // MJExtensionExample
4 | //
5 | // Created by MJ Lee on 15/6/7.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "NSString+MJExtension.h"
10 |
11 | @implementation NSString (MJExtension)
12 | - (NSString *)mj_underlineFromCamel
13 | {
14 | if (self.length == 0) return self;
15 | NSMutableString *string = [NSMutableString string];
16 | for (NSUInteger i = 0; i= 2) [string appendString:[cmp substringFromIndex:1]];
40 | } else {
41 | [string appendString:cmp];
42 | }
43 | }
44 | return string;
45 | }
46 |
47 | - (NSString *)mj_firstCharLower
48 | {
49 | if (self.length == 0) return self;
50 | NSMutableString *string = [NSMutableString string];
51 | [string appendString:[NSString stringWithFormat:@"%c", [self characterAtIndex:0]].lowercaseString];
52 | if (self.length >= 2) [string appendString:[self substringFromIndex:1]];
53 | return string;
54 | }
55 |
56 | - (NSString *)mj_firstCharUpper
57 | {
58 | if (self.length == 0) return self;
59 | NSMutableString *string = [NSMutableString string];
60 | [string appendString:[NSString stringWithFormat:@"%c", [self characterAtIndex:0]].uppercaseString];
61 | if (self.length >= 2) [string appendString:[self substringFromIndex:1]];
62 | return string;
63 | }
64 |
65 | - (BOOL)mj_isPureInt
66 | {
67 | NSScanner *scan = [NSScanner scannerWithString:self];
68 | int val;
69 | return [scan scanInt:&val] && [scan isAtEnd];
70 | }
71 |
72 | - (NSURL *)mj_url
73 | {
74 | // [self stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet characterSetWithCharactersInString:@"!$&'()*+,-./:;=?@_~%#[]"]];
75 |
76 | return [NSURL URLWithString:(NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)self, (CFStringRef)@"!$&'()*+,-./:;=?@_~%#[]", NULL,kCFStringEncodingUTF8))];
77 | }
78 | @end
79 |
80 | @implementation NSString (MJExtensionDeprecated_v_2_5_16)
81 | - (NSString *)underlineFromCamel
82 | {
83 | return self.mj_underlineFromCamel;
84 | }
85 |
86 | - (NSString *)camelFromUnderline
87 | {
88 | return self.mj_camelFromUnderline;
89 | }
90 |
91 | - (NSString *)firstCharLower
92 | {
93 | return self.mj_firstCharLower;
94 | }
95 |
96 | - (NSString *)firstCharUpper
97 | {
98 | return self.mj_firstCharUpper;
99 | }
100 |
101 | - (BOOL)isPureInt
102 | {
103 | return self.mj_isPureInt;
104 | }
105 |
106 | - (NSURL *)url
107 | {
108 | return self.mj_url;
109 | }
110 | @end
111 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/UIView+Extension.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+Extension.h
3 | //
4 | //
5 | // Created by YANG-ZF on 16/1/8.
6 | // Copyright © 2016年 qq 316917975 . All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface UIView (Extension)
12 | @property (nonatomic, assign) CGFloat x;
13 | @property (nonatomic, assign) CGFloat y;
14 | @property (nonatomic, assign) CGFloat width;
15 | @property (nonatomic, assign) CGFloat height;
16 | @property (nonatomic, assign) CGFloat centerX;
17 | @property (nonatomic, assign) CGFloat centerY;
18 | @end
19 |
20 | @interface UILabel(Extension)
21 |
22 | +(instancetype)labelWithFont:(UIFont *)font textColor:(UIColor *)textColor textAlignment:(NSTextAlignment)textAlignment numberOfLines:(NSInteger)numberOfLines;
23 |
24 | @end
--------------------------------------------------------------------------------
/ZFVoteViewDemo/UIView+Extension.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+Extension.m
3 | //
4 | //
5 | // Created by YANG-ZF on 16/1/8.
6 | // Copyright © 2016年 qq 316917975 . All rights reserved.
7 | //
8 |
9 | #import "UIView+Extension.h"
10 |
11 |
12 | @implementation UIView (Extension)
13 |
14 |
15 | - (void)setX:(CGFloat)x
16 | {
17 | CGRect frame = self.frame;
18 | frame.origin.x = x;
19 | self.frame = frame;
20 | }
21 |
22 | - (CGFloat)x
23 | {
24 | return self.frame.origin.x;
25 | }
26 |
27 | - (void)setY:(CGFloat)y
28 | {
29 | CGRect frame = self.frame;
30 | frame.origin.y = y;
31 | self.frame = frame;
32 | }
33 |
34 | - (CGFloat)y
35 | {
36 | return self.frame.origin.y;
37 | }
38 |
39 | - (void)setWidth:(CGFloat)width
40 | {
41 | CGRect frame = self.frame;
42 | frame.size.width = width;
43 | self.frame = frame;
44 | }
45 |
46 | - (CGFloat)width
47 | {
48 | return self.frame.size.width;
49 | }
50 |
51 | - (void)setHeight:(CGFloat)height
52 | {
53 | CGRect frame = self.frame;
54 | frame.size.height = height;
55 | self.frame = frame;
56 | }
57 |
58 | - (CGFloat)height
59 | {
60 | return self.frame.size.height;
61 | }
62 |
63 | - (void)setCenterX:(CGFloat)centerX
64 | {
65 | CGPoint center = self.center;
66 | center.x = centerX;
67 | self.center = center;
68 | }
69 |
70 | - (CGFloat)centerX
71 | {
72 | return self.center.x;
73 | }
74 |
75 | - (void)setCenterY:(CGFloat)centerY
76 | {
77 | CGPoint center = self.center;
78 | center.y = centerY;
79 | self.center = center;
80 | }
81 |
82 | - (CGFloat)centerY
83 | {
84 | return self.center.y;
85 | }
86 |
87 | @end
88 |
89 |
90 | @implementation UILabel(Extension)
91 |
92 | +(instancetype)labelWithFont:(UIFont *)font textColor:(UIColor *)textColor textAlignment:(NSTextAlignment)textAlignment numberOfLines:(NSInteger)numberOfLines{
93 | UILabel *label = [[UILabel alloc]init];
94 | label.font = font;
95 | label.textColor = textColor;
96 | label.textAlignment = textAlignment;
97 | label.numberOfLines = numberOfLines;
98 |
99 | return label;
100 | }
101 |
102 | @end
103 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // ZFVoteViewDemo
4 | //
5 | // Created by MAC_PRO on 16/8/18.
6 | // Copyright © 2016年 ZFbory. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // ZFVoteViewDemo
4 | //
5 | // Created by MAC_PRO on 16/8/18.
6 | // Copyright © 2016年 ZFbory. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 | #import "MJExtension.h"
11 | #import "ZFVoteModel.h"
12 | #import "ZFVoteCell.h"
13 | #import "ZFConfig.h"
14 | #import "UIView+Extension.h"
15 | #import "ZFVoteView.h"
16 | #import "ZFVoteTableView.h"
17 |
18 | @interface ViewController ()
19 |
20 | @property (nonatomic,strong) NSMutableArray *list;
21 |
22 | @property (nonatomic,weak) UITableView *tableView;
23 |
24 | @end
25 |
26 | @implementation ViewController
27 |
28 | - (void)viewDidLoad {
29 | [super viewDidLoad];
30 |
31 | // self.view.backgroundColor = [UIColor groupTableViewBackgroundColor];
32 |
33 | [self loadNewData];
34 |
35 | [self setupTableView];
36 |
37 | }
38 |
39 | -(NSMutableArray *)list{
40 |
41 | if (!_list) {
42 |
43 | _list = [NSMutableArray array];
44 | }
45 | return _list;
46 | }
47 | -(void)loadNewData{
48 |
49 | //模拟延迟加载
50 | typeof(self) weakSelf = self;
51 |
52 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
53 |
54 | NSString *path = [[NSBundle mainBundle] pathForResource:@"abc.plist" ofType:nil];
55 |
56 | NSDictionary *votesDic = [NSDictionary dictionaryWithContentsOfFile:path];
57 |
58 | weakSelf.list = [ZFVoteModel mj_objectArrayWithKeyValuesArray:votesDic[@"data"][@"list"]];
59 |
60 | [weakSelf.tableView reloadData];
61 |
62 | });
63 |
64 | }
65 | -(void)setupTableView{
66 |
67 |
68 | ZFVoteTableView *tableVew = [[ZFVoteTableView alloc]initWithFrame:CGRectMake(20,
69 | 100,
70 | ZFVoteTableViewMax_W,
71 | 400)//这里最好是得到数据算出的总高度
72 | style:UITableViewStylePlain];
73 |
74 | tableVew.delegate = self;
75 | tableVew.dataSource = self;
76 | self.tableView = tableVew;
77 | [self.view addSubview:tableVew];
78 |
79 | }
80 |
81 |
82 | -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
83 |
84 | return self.list.count;
85 |
86 | }
87 |
88 |
89 |
90 | -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
91 |
92 | ZFVoteModel *voteModel = self.list[indexPath.row];
93 |
94 | static NSString *ZFVoteCellIdentifier = @"ZFVoteCellIdentifier";
95 |
96 | ZFVoteCell *cell = [tableView dequeueReusableCellWithIdentifier:ZFVoteCellIdentifier];
97 |
98 | if (!cell) {
99 |
100 | cell = [[ZFVoteCell alloc]initWithStyle:UITableViewCellStyleDefault
101 | reuseIdentifier:ZFVoteCellIdentifier];
102 | }
103 |
104 | cell.voteModel = voteModel;
105 |
106 | return cell;
107 |
108 | }
109 |
110 | -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
111 |
112 | ZFVoteModel *voteModel = self.list[indexPath.row];
113 |
114 | return voteModel.voteCell_H;
115 |
116 | }
117 | #pragma mark - 核心动画效果实现步骤
118 | -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
119 |
120 | [self refreshDataAtIndexPath:indexPath];//刷新数据
121 |
122 |
123 | ZFVoteModel *voteModel = self.list[indexPath.row];
124 |
125 | ZFVoteCell *selectedCell = [_tableView cellForRowAtIndexPath:indexPath];
126 | if (indexPath.row == 0) {
127 | [selectedCell thumbUpstartAnimation];
128 | return;
129 | }
130 |
131 | ZFVoteView *voteView = [[ZFVoteView alloc]initWithFrame:selectedCell.frame
132 | voteView:voteModel];
133 | voteView.layer.masksToBounds = NO;
134 | [self.tableView addSubview:voteView];
135 | self.tableView.userInteractionEnabled = NO;
136 |
137 |
138 | [UIView animateWithDuration:0.4
139 | animations:^{
140 |
141 | voteView.transform = CGAffineTransformMakeScale(1.05, 1.05);
142 |
143 | }completion:^(BOOL finished) {
144 |
145 | [UIView animateWithDuration:0.7
146 | animations:^{
147 |
148 | [self.list removeObject:voteModel];
149 | [self.list insertObject:voteModel atIndex:0];
150 | [self.tableView moveRowAtIndexPath:indexPath
151 | toIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
152 | voteView.centerY = selectedCell.centerY;
153 | voteView.centerX = selectedCell.centerX;
154 |
155 | }completion:^(BOOL finished) {
156 |
157 | [UIView animateWithDuration:0.4
158 | animations:^{
159 |
160 | voteView.transform = CGAffineTransformIdentity;
161 |
162 | }completion:^(BOOL finished) {
163 |
164 | [voteView removeFromSuperview];
165 | self.tableView.userInteractionEnabled = YES;
166 |
167 | }];
168 | }];
169 | }];
170 |
171 | }
172 |
173 | #pragma mark - 模拟刷新数据
174 | -(void)refreshDataAtIndexPath:(NSIndexPath *)indexPath{
175 |
176 | ZFVoteModel *voteModel = self.list[indexPath.row];
177 |
178 | [self.list enumerateObjectsUsingBlock:^(ZFVoteModel *obj, NSUInteger idx, BOOL * _Nonnull stop) {
179 | if (voteModel.isselected) {//说明是取消选中
180 | obj.isvote = NO;
181 | if (obj == voteModel) {
182 | obj.votes = @([obj.votes integerValue] - 40);
183 | }
184 | obj.totalVotes = @([obj.totalVotes integerValue] - 40);
185 | }else{
186 | if (obj.isselected) {
187 | obj.votes = @([obj.votes integerValue] - 40);
188 | }
189 | if (obj == voteModel ) {
190 | obj.votes = @([obj.votes integerValue] + 40);
191 | }
192 | if (!obj.isvote) {
193 | obj.totalVotes = @([obj.totalVotes integerValue] + 40);
194 | }
195 |
196 | obj.isvote = YES;
197 | }
198 | if (voteModel != obj) {
199 |
200 | obj.isselected = NO;
201 | }
202 | }];
203 |
204 | voteModel.isselected = !voteModel.isselected;
205 |
206 | [self.tableView reloadData];
207 |
208 | }
209 |
210 | @end
211 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/ZFConfig.h:
--------------------------------------------------------------------------------
1 | //
2 | // ZFConst.h
3 | // ZFVoteViewDemo
4 | //
5 | // Created by MAC_PRO on 16/8/18.
6 | // Copyright © 2016年 ZFbory. All rights reserved.
7 | //
8 |
9 |
10 | #define ZFScreenW [UIScreen mainScreen].bounds.size.width//屏幕宽
11 |
12 | #define ZFScreenH [UIScreen mainScreen].bounds.size.height//屏幕高
13 |
14 | #define ZFVoteTableViewMax_W [UIScreen mainScreen].bounds.size.width - 40
15 |
16 | #define percentLable_W 40
17 |
18 | #define thumbUpView_WH 25
19 |
20 | #define ZFBlueColor [UIColor colorWithRed:31.0 / 255.0 green:149.0 / 255.0 blue:255.0 /255.0 alpha:1] //深蓝色
21 |
22 | #define ZFlightBlueColor [UIColor colorWithRed:31.0 / 255.0 green:149.0 / 255.0 blue:255.0 /255.0 alpha:0.5] //深蓝色
23 |
24 | #define ZFVoteCellLeftRightInset 15 //cell左右边的内边距
25 |
26 | #define ZFVoteCellTopBottomInset 5 //cell左右边的内边距
27 |
28 | #define ZFCornerRadius 5 //控件圆角大小
--------------------------------------------------------------------------------
/ZFVoteViewDemo/ZFPercentBar.h:
--------------------------------------------------------------------------------
1 | //
2 | // ZFPercentBar.h
3 | // ZFVoteViewDemo
4 | //
5 | // Created by MAC_PRO on 16/8/18.
6 | // Copyright © 2016年 ZFbory. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ZFPercentBar : UIView
12 |
13 |
14 | @property (nonatomic, assign) CGFloat percentage;
15 |
16 | @property (nonatomic, strong) UIColor *foregroundColor;
17 |
18 | - (void)reset;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/ZFPercentBar.m:
--------------------------------------------------------------------------------
1 | //
2 | // ZFPercentBar.m
3 | // ZFVoteViewDemo
4 | //
5 | // Created by MAC_PRO on 16/8/18.
6 | // Copyright © 2016年 ZFbory. All rights reserved.
7 | //
8 |
9 | #import "ZFPercentBar.h"
10 |
11 | #import
12 |
13 | @interface ZFPercentBar ()
14 |
15 | @property (nonatomic, assign) BOOL animated;
16 |
17 | @property (nonatomic, assign) CFTimeInterval animationDuration;
18 |
19 | @end
20 |
21 | @implementation ZFPercentBar
22 |
23 | - (id)initWithFrame:(CGRect)frame {
24 | self = [super initWithFrame:frame];
25 | if (self) {
26 | self.animated = YES;
27 | self.animationDuration = 0.5;
28 | self.layer.cornerRadius = 5.0;
29 | self.layer.masksToBounds = YES;
30 | self.backgroundColor = [UIColor whiteColor];
31 | _percentage = 0;
32 | }
33 | return self;
34 | }
35 |
36 |
37 | - (void)setPercentage:(CGFloat)percentage animated:(BOOL)animated {
38 | self.animated = animated;
39 | self.percentage = percentage;
40 | self.animated = YES;
41 | }
42 |
43 | - (void)setPercentage:(CGFloat)percentage {
44 | if (percentage == _percentage) return;
45 | if (percentage >= 100) percentage = 100;
46 | if (percentage <= 0) percentage = 0;
47 |
48 | [self progressBarTo:percentage];
49 | _percentage = percentage;
50 | }
51 |
52 | - (void)progressBarTo:(CGFloat)value {
53 |
54 |
55 | UIBezierPath *path = [UIBezierPath bezierPath];
56 | CGFloat startY = self.frame.size.height / 2;
57 | CGFloat startX = (self.frame.size.width * (_percentage / 100));
58 | CGFloat endX = (self.frame.size.width * value/100);
59 | if (_percentage > value){
60 | [path moveToPoint:CGPointMake(startX+1, startY)];
61 | [path addLineToPoint:CGPointMake(endX+1, startY)];
62 | }else{
63 | [path moveToPoint:CGPointMake(startX-1, startY)];
64 | [path addLineToPoint:CGPointMake(endX, startY)];
65 | }
66 |
67 |
68 | CAShapeLayer *layer = [CAShapeLayer layer];
69 | layer.lineWidth = self.frame.size.height;
70 | layer.path = path.CGPath;
71 | layer.strokeColor = self.foregroundColor.CGColor;
72 |
73 | if (_percentage > value) layer.strokeColor = [self.backgroundColor CGColor];
74 |
75 | [self.layer addSublayer:layer];
76 |
77 | if (!self.animated) return;
78 |
79 | CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
80 | animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
81 | animation.duration = self.animationDuration;
82 | animation.fromValue = @(0);
83 | animation.toValue = @(1);
84 | animation.delegate = self;
85 | [layer addAnimation:animation forKey:@"strokeEndAnimation"];
86 |
87 | }
88 |
89 |
90 | - (void)setForegroundColor:(UIColor *)foregroundColor {
91 | _foregroundColor = foregroundColor;
92 |
93 | self.layer.sublayers = nil;
94 | CGFloat temp = _percentage;
95 | [self setPercentage:0 animated:NO];
96 | [self setPercentage:temp animated:NO];
97 | }
98 |
99 | - (void)reset {
100 |
101 | self.percentage = 0;
102 |
103 | typeof(self) weakSelf = self;
104 |
105 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.animationDuration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
106 |
107 | weakSelf.layer.sublayers = nil;
108 |
109 | });
110 | }
111 |
112 | @end
113 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/ZFVoteCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // ZFVoteCell.h
3 | // ZFVoteViewDemo
4 | //
5 | // Created by MAC_PRO on 16/8/18.
6 | // Copyright © 2016年 ZFbory. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "ZFVoteModel.h"
11 | @interface ZFVoteCell : UITableViewCell
12 |
13 | /**voteModel*/
14 | @property (nonatomic, strong) ZFVoteModel *voteModel;
15 |
16 | -(void)thumbUpstartAnimation;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/ZFVoteCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // ZFVoteCell.m
3 | // ZFVoteViewDemo
4 | //
5 | // Created by MAC_PRO on 16/8/18.
6 | // Copyright © 2016年 ZFbory. All rights reserved.
7 | //
8 |
9 | #import "ZFVoteCell.h"
10 | #import "ZFConfig.h"
11 | #import "UIView+Extension.h"
12 | #import "ZFVoteView.h"
13 |
14 | @interface ZFVoteCell ()
15 |
16 | @property (nonatomic,weak) ZFVoteView *voteView;
17 |
18 | @end
19 |
20 | @implementation ZFVoteCell
21 |
22 | -(instancetype)initWithStyle:(UITableViewCellStyle)style
23 | reuseIdentifier:(NSString *)reuseIdentifier{
24 |
25 | self = [super initWithStyle:style
26 | reuseIdentifier:reuseIdentifier];
27 | if (self) {
28 |
29 | self.backgroundColor = [UIColor whiteColor];
30 | self.selectionStyle = UITableViewCellSelectionStyleNone;
31 | self.layer.borderColor = [UIColor lightGrayColor].CGColor;
32 | self.layer.borderWidth = 0.5;
33 | self.layer.cornerRadius = ZFCornerRadius;
34 | self.layer.masksToBounds = YES;
35 |
36 |
37 | [self setupVoteView];//初始化投票主控件
38 |
39 | }
40 | return self;
41 | }
42 |
43 | -(void)setupVoteView{
44 |
45 | ZFVoteView *voteView = [[ZFVoteView alloc]initWithFrame:self.bounds
46 | voteView:nil];
47 | self.voteView = voteView;
48 |
49 | [self addSubview:voteView];
50 | }
51 |
52 | -(void)layoutSubviews{
53 |
54 | [super layoutSubviews];
55 |
56 | self.voteView.frame = self.bounds;
57 | }
58 |
59 |
60 | -(void)setVoteModel:(ZFVoteModel *)voteModel{
61 |
62 | _voteModel = voteModel;
63 |
64 | self.voteView.voteModel = _voteModel;
65 |
66 | }
67 |
68 | -(void)thumbUpstartAnimation{
69 |
70 | [self.voteView thumbUpstartAnimation];
71 |
72 | }
73 |
74 | -(void)setFrame:(CGRect)frame{
75 |
76 | if (frame.size.width == ZFVoteTableViewMax_W) {//初始化就设置cell的内边距
77 |
78 | frame = UIEdgeInsetsInsetRect(frame,
79 | UIEdgeInsetsMake(ZFVoteCellTopBottomInset,
80 | ZFVoteCellLeftRightInset,
81 | ZFVoteCellTopBottomInset,
82 | ZFVoteCellLeftRightInset));
83 | }else{//重复利用的时候改变它的x值
84 |
85 | frame.origin.x += ZFVoteCellLeftRightInset;
86 | }
87 | [super setFrame:frame];
88 | }
89 |
90 |
91 |
92 | @end
93 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/ZFVoteModel.h:
--------------------------------------------------------------------------------
1 | //
2 | // ZFVoteModel.h
3 | // ZFVoteViewDemo
4 | //
5 | // Created by MAC_PRO on 16/8/18.
6 | // Copyright © 2016年 ZFbory. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface ZFVoteModel : NSObject
13 |
14 | /**投票数量*/
15 | @property (nonatomic, strong) NSNumber *votes;
16 |
17 | /**总投票数量*/
18 | @property (nonatomic, strong) NSNumber *totalVotes;
19 |
20 | /**投票标题*/
21 | @property (nonatomic, copy) NSString *title;
22 |
23 | /**是否自己已经投票*/
24 | @property (nonatomic, assign) BOOL isvote;
25 |
26 | /**是否自己已经选择*/
27 | @property (nonatomic, assign) BOOL isselected;
28 |
29 | /**投票cell的高度*/
30 | @property (nonatomic, assign) CGFloat voteCell_H;
31 |
32 | @end
33 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/ZFVoteModel.m:
--------------------------------------------------------------------------------
1 | //
2 | // ZFVoteModel.m
3 | // ZFVoteViewDemo
4 | //
5 | // Created by MAC_PRO on 16/8/18.
6 | // Copyright © 2016年 ZFbory. All rights reserved.
7 | //
8 |
9 | #import "ZFVoteModel.h"
10 | #import "ZFConfig.h"
11 |
12 | @implementation ZFVoteModel
13 |
14 |
15 | -(void)setTitle:(NSString *)title{//根据数据算出每行cell的实际高度
16 |
17 | _title = title;
18 |
19 | CGFloat title_H = [title boundingRectWithSize:CGSizeMake(ZFVoteTableViewMax_W - percentLable_W - thumbUpView_WH - 85, 100)
20 | options:NSStringDrawingUsesFontLeading|NSStringDrawingUsesLineFragmentOrigin
21 | attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:15.0]}
22 | context:nil].size.height;
23 |
24 | self.voteCell_H = title_H + 30;
25 | }
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/ZFVoteTableView.h:
--------------------------------------------------------------------------------
1 | //
2 | // ZFVoteTableView.h
3 | // ZFVoteViewDemo
4 | //
5 | // Created by MAC_PRO on 16/8/22.
6 | // Copyright © 2016年 ZFbory. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ZFVoteTableView : UITableView
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/ZFVoteTableView.m:
--------------------------------------------------------------------------------
1 | //
2 | // ZFVoteTableView.m
3 | // ZFVoteViewDemo
4 | //
5 | // Created by MAC_PRO on 16/8/22.
6 | // Copyright © 2016年 ZFbory. All rights reserved.
7 | //
8 |
9 | #import "ZFVoteTableView.h"
10 |
11 | @implementation ZFVoteTableView
12 |
13 | -(instancetype)initWithFrame:(CGRect)frame
14 | style:(UITableViewStyle)style{
15 |
16 | self = [super initWithFrame:frame
17 | style:style];
18 | if (self) {
19 |
20 | self.separatorStyle = UITableViewCellSeparatorStyleNone;
21 |
22 | self.bounces = NO;
23 | }
24 | return self;
25 | }
26 | @end
27 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/ZFVoteView.h:
--------------------------------------------------------------------------------
1 | //
2 | // ZFVoteView.h
3 | // ZFVoteViewDemo
4 | //
5 | // Created by MAC_PRO on 16/8/19.
6 | // Copyright © 2016年 ZFbory. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "ZFVoteModel.h"
11 | @interface ZFVoteView : UIView
12 |
13 | -(instancetype)initWithFrame:(CGRect)frame voteView:(ZFVoteModel *)voteModel;
14 |
15 | @property (nonatomic, strong) ZFVoteModel *voteModel;
16 |
17 | - (void)thumbUpstartAnimation;
18 | @end
19 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/ZFVoteView.m:
--------------------------------------------------------------------------------
1 | //
2 | // ZFVoteView.m
3 | // ZFVoteViewDemo
4 | //
5 | // Created by MAC_PRO on 16/8/19.
6 | // Copyright © 2016年 ZFbory. All rights reserved.
7 | //
8 |
9 | #import "ZFVoteView.h"
10 | #import "ZFConfig.h"
11 | #import "ZFPercentBar.h"
12 | #import "UIView+Extension.h"
13 |
14 | @interface ZFVoteView ()
15 |
16 | @property (nonatomic,weak) UILabel *voteLabel;
17 |
18 | @property (nonatomic,weak) UILabel *percentLable;
19 |
20 | @property (nonatomic,weak) UIImageView *thumbUpView;
21 |
22 | @property (nonatomic,weak) ZFPercentBar *bar;
23 | @end
24 |
25 | @implementation ZFVoteView
26 |
27 | -(instancetype)initWithFrame:(CGRect)frame voteView:(ZFVoteModel *)voteModel{
28 |
29 | if (self = [super initWithFrame:frame]) {
30 |
31 | self.backgroundColor = [UIColor whiteColor];
32 |
33 | self.layer.cornerRadius = ZFCornerRadius;
34 |
35 | self.layer.shadowOffset = CGSizeMake(-2.0, 0.0);
36 |
37 | self.layer.shadowRadius = 5.0;
38 |
39 | self.layer.shadowOpacity = 0.4;
40 |
41 | self.layer.masksToBounds = YES;
42 |
43 | [self initSubviews];
44 |
45 | self.voteModel = voteModel;
46 |
47 | if (self.voteModel) [self thumbUpstartAnimation];//有数据说明是要选中,给大拇指控件动画效果
48 |
49 | }
50 | return self;
51 | }
52 |
53 | -(void)initSubviews{
54 |
55 | ZFPercentBar *bar = [[ZFPercentBar alloc]initWithFrame:self.bounds];
56 |
57 | self.bar = bar;
58 | [self addSubview:bar];
59 |
60 |
61 |
62 | UIImageView *thumbUpView = [[UIImageView alloc]init];
63 |
64 | self.thumbUpView = thumbUpView;
65 | [self addSubview:thumbUpView];
66 |
67 |
68 | UILabel *percentLable = [UILabel labelWithFont:[UIFont systemFontOfSize:13.0]
69 | textColor:[UIColor lightGrayColor]
70 | textAlignment:NSTextAlignmentRight
71 | numberOfLines:1];
72 |
73 | self.percentLable = percentLable;
74 | [self addSubview:percentLable];
75 |
76 |
77 | UILabel *voteLabel = [UILabel labelWithFont:[UIFont systemFontOfSize:15.0]
78 | textColor:[UIColor blackColor]
79 | textAlignment:NSTextAlignmentLeft
80 | numberOfLines:0];
81 | self.voteLabel = voteLabel;
82 | [self addSubview:voteLabel];
83 |
84 | }
85 |
86 |
87 |
88 | -(void)layoutSubviews{
89 |
90 | [super layoutSubviews];
91 |
92 |
93 | self.bar.frame = self.bounds;
94 |
95 | self.percentLable.x = ZFVoteTableViewMax_W - percentLable_W - thumbUpView_WH - 60;
96 | self.percentLable.y = 0;
97 | self.percentLable.width = percentLable_W;
98 | self.percentLable.height = self.height;
99 |
100 |
101 | self.thumbUpView.x = ZFVoteTableViewMax_W - thumbUpView_WH - 45;
102 | self.thumbUpView.width = thumbUpView_WH;
103 | self.thumbUpView.height = thumbUpView_WH;
104 | self.thumbUpView.centerY = self.height * 0.5;
105 |
106 |
107 | self.voteLabel.height = self.height;
108 | self.voteLabel.x = ZFVoteCellLeftRightInset;
109 | self.voteLabel.y = 0;
110 | self.voteLabel.width = self.width -(percentLable_W + thumbUpView_WH + 50);
111 |
112 | }
113 | - (void)thumbUpstartAnimation{
114 |
115 | self.thumbUpView.transform = CGAffineTransformIdentity;
116 |
117 | [UIView animateKeyframesWithDuration: 0.5 delay: 0 options: 0 animations: ^{
118 |
119 | [UIView addKeyframeWithRelativeStartTime: 0
120 | relativeDuration: 1 / 3.0
121 | animations: ^{
122 |
123 | self.thumbUpView.transform = CGAffineTransformMakeScale(1.5, 1.5);
124 | }];
125 | [UIView addKeyframeWithRelativeStartTime: 1 / 3.0
126 | relativeDuration: 1 / 3.0
127 | animations: ^{
128 |
129 | self.thumbUpView.transform = CGAffineTransformMakeScale(0.8, 0.8);
130 | }];
131 | [UIView addKeyframeWithRelativeStartTime: 2 / 3.0
132 | relativeDuration: 1 / 3.0
133 | animations: ^{
134 |
135 | self.thumbUpView.transform = CGAffineTransformMakeScale(1.0, 1.0);
136 | }];
137 | } completion: ^(BOOL finished) {
138 |
139 | }];
140 |
141 | }
142 |
143 |
144 | -(void)setVoteModel:(ZFVoteModel *)voteModel{
145 |
146 | _voteModel = voteModel;
147 |
148 | self.voteLabel.text = _voteModel.title;
149 |
150 | self.percentLable.text = [NSString stringWithFormat:@"%.f%%",([_voteModel.votes floatValue] / [_voteModel.totalVotes floatValue] * 100)];
151 |
152 | self.percentLable.textColor = _voteModel.isselected?ZFBlueColor:[UIColor lightGrayColor];
153 |
154 | self.thumbUpView.image = _voteModel.isselected?[UIImage imageNamed:@"Like-Blue"]:[UIImage imageNamed:@"Like-PlaceHold"];
155 |
156 | if (_voteModel.isvote) {//自己有投票
157 |
158 | self.bar.foregroundColor = _voteModel.isselected?ZFBlueColor:ZFlightBlueColor;
159 |
160 | self.bar.percentage = ([_voteModel.votes floatValue] / [_voteModel.totalVotes floatValue] * 100);
161 |
162 | }else{
163 |
164 | [self.bar reset];
165 | }
166 |
167 | }
168 |
169 | @end
170 |
171 |
--------------------------------------------------------------------------------
/ZFVoteViewDemo/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // ZFVoteViewDemo
4 | //
5 | // Created by MAC_PRO on 16/8/18.
6 | // Copyright © 2016年 ZFbory. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/ZFVoteViewDemoTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ZFVoteViewDemoTests/ZFVoteViewDemoTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // ZFVoteViewDemoTests.m
3 | // ZFVoteViewDemoTests
4 | //
5 | // Created by MAC_PRO on 16/8/18.
6 | // Copyright © 2016年 ZFbory. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ZFVoteViewDemoTests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation ZFVoteViewDemoTests
16 |
17 | - (void)setUp {
18 | [super setUp];
19 | // Put setup code here. This method is called before the invocation of each test method in the class.
20 | }
21 |
22 | - (void)tearDown {
23 | // Put teardown code here. This method is called after the invocation of each test method in the class.
24 | [super tearDown];
25 | }
26 |
27 | - (void)testExample {
28 | // This is an example of a functional test case.
29 | // Use XCTAssert and related functions to verify your tests produce the correct results.
30 | }
31 |
32 | - (void)testPerformanceExample {
33 | // This is an example of a performance test case.
34 | [self measureBlock:^{
35 | // Put the code you want to measure the time of here.
36 | }];
37 | }
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/ZFVoteViewDemoUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ZFVoteViewDemoUITests/ZFVoteViewDemoUITests.m:
--------------------------------------------------------------------------------
1 | //
2 | // ZFVoteViewDemoUITests.m
3 | // ZFVoteViewDemoUITests
4 | //
5 | // Created by MAC_PRO on 16/8/18.
6 | // Copyright © 2016年 ZFbory. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ZFVoteViewDemoUITests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation ZFVoteViewDemoUITests
16 |
17 | - (void)setUp {
18 | [super setUp];
19 |
20 | // Put setup code here. This method is called before the invocation of each test method in the class.
21 |
22 | // In UI tests it is usually best to stop immediately when a failure occurs.
23 | self.continueAfterFailure = NO;
24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
25 | [[[XCUIApplication alloc] init] launch];
26 |
27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
28 | }
29 |
30 | - (void)tearDown {
31 | // Put teardown code here. This method is called after the invocation of each test method in the class.
32 | [super tearDown];
33 | }
34 |
35 | - (void)testExample {
36 | // Use recording to get started writing UI tests.
37 | // Use XCTAssert and related functions to verify your tests produce the correct results.
38 | }
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/abc.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | data
6 |
7 | list
8 |
9 |
10 | isselected
11 |
12 | isvote
13 |
14 | votes
15 | 320
16 | totalVotes
17 | 700
18 | title
19 | 运动员里尽有这么美好的肉体
20 |
21 |
22 | totalVotes
23 | 700
24 | isselected
25 |
26 | isvote
27 |
28 | votes
29 | 170
30 | title
31 | 收获一大堆表情包(跪谢傅爷恩惠)
32 |
33 |
34 | totalVotes
35 | 700
36 | isselected
37 |
38 | isvote
39 |
40 | votes
41 | 156
42 | title
43 | 吴敏霞有这么帅男票
44 |
45 |
46 | totalVotes
47 | 700
48 | isselected
49 |
50 | isvote
51 |
52 | votes
53 | 115
54 | title
55 | 气枪的靶这么小(跟个啤酒瓶底差不多)
56 |
57 |
58 | totalVotes
59 | 700
60 | isselected
61 |
62 | isvote
63 |
64 | votes
65 | 266
66 | title
67 | 记者越来越不好当
68 |
69 |
70 | totalVotes
71 | 700
72 | isselected
73 |
74 | isvote
75 |
76 | votes
77 | 88
78 | title
79 | 原来办奥运会可以这么省
80 |
81 |
82 | totalVotes
83 | 700
84 | isselected
85 |
86 | isvote
87 |
88 | votes
89 | 210
90 | title
91 | 男神的最低标准是会游泳
92 |
93 |
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/格瓦拉投票效果1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZFbaby/ZFVoteViewDemo/dcf12ee9fd89b77ffffa7b7cbcfebb8e8a339b41/格瓦拉投票效果1.gif
--------------------------------------------------------------------------------
/格瓦拉投票效果2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZFbaby/ZFVoteViewDemo/dcf12ee9fd89b77ffffa7b7cbcfebb8e8a339b41/格瓦拉投票效果2.gif
--------------------------------------------------------------------------------
/格瓦拉投票效果3.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZFbaby/ZFVoteViewDemo/dcf12ee9fd89b77ffffa7b7cbcfebb8e8a339b41/格瓦拉投票效果3.gif
--------------------------------------------------------------------------------