├── TextUtil ├── Images │ ├── 001.png │ ├── 002.png │ ├── 003.png │ ├── 004.png │ ├── 005.png │ ├── 006.png │ ├── 007.png │ ├── 008.png │ ├── 009.png │ ├── 010.png │ ├── 011.png │ ├── 012.png │ ├── 013.png │ ├── 014.png │ ├── 015.png │ ├── 016.png │ ├── 017.png │ ├── 018.png │ ├── 019.png │ ├── 020.png │ ├── 021@2x.png │ ├── 022@2x.png │ ├── 023@2x.png │ ├── 024@2x.png │ ├── 025@2x.png │ ├── 026@2x.png │ ├── 027@2x.png │ ├── 028@2x.png │ ├── 029@2x.png │ ├── 030@2x.png │ ├── 031@2x.png │ ├── 032@2x.png │ ├── 033@2x.png │ ├── 034@2x.png │ ├── 035@2x.png │ ├── 036@2x.png │ ├── 037@2x.png │ ├── 038@2x.png │ ├── 039@2x.png │ ├── 040@2x.png │ ├── 041@2x.png │ ├── 042@2x.png │ ├── 043@2x.png │ ├── 044@2x.png │ ├── 045@2x.png │ ├── 046@2x.png │ ├── 047@2x.png │ ├── 048@2x.png │ ├── 049@2x.png │ ├── 050@2x.png │ ├── 051@2x.png │ ├── 052@2x.png │ ├── 053@2x.png │ ├── 054@2x.png │ ├── 055@2x.png │ ├── 056@2x.png │ ├── 057@2x.png │ ├── 058@2x.png │ ├── 059@2x.png │ ├── 060@2x.png │ ├── 061@2x.png │ ├── 062@2x.png │ ├── 063@2x.png │ ├── 064@2x.png │ ├── 065@2x.png │ ├── 066@2x.png │ ├── 067@2x.png │ ├── 068@2x.png │ ├── 069@2x.png │ ├── 070@2x.png │ ├── 071@2x.png │ ├── 072@2x.png │ ├── 073@2x.png │ ├── 074@2x.png │ ├── 075@2x.png │ ├── 076@2x.png │ ├── 077@2x.png │ ├── 078@2x.png │ ├── 079@2x.png │ ├── 080@2x.png │ ├── 081@2x.png │ ├── 082@2x.png │ ├── 083@2x.png │ ├── 084@2x.png │ ├── 085@2x.png │ ├── 086@2x.png │ ├── 087@2x.png │ ├── 088@2x.png │ ├── 089@2x.png │ ├── 090@2x.png │ ├── 091@2x.png │ ├── 092@2x.png │ ├── 093@2x.png │ ├── 094@2x.png │ ├── 095@2x.png │ ├── 096@2x.png │ ├── 097@2x.png │ ├── 098@2x.png │ ├── 099@2x.png │ ├── 100@2x.png │ ├── 101@2x.png │ ├── 102@2x.png │ ├── 103@2x.png │ ├── 104@2x.png │ ├── 105@2x.png │ ├── image_01.jpg │ ├── image_02.jpg │ ├── image_03.jpg │ ├── image_04.jpg │ ├── image_05.jpg │ ├── image_06.jpg │ ├── image_07.jpg │ ├── image_08.jpg │ ├── image_09.jpg │ ├── emotion@2x.png │ ├── ScreenShot1.png │ ├── ScreenShot2.png │ └── ScreenShot3.png ├── Images.xcassets │ ├── image │ │ ├── tab_oa.imageset │ │ │ ├── tab_oa@2x.png │ │ │ ├── tab_oa@3x.png │ │ │ └── Contents.json │ │ ├── header_QQ.imageset │ │ │ ├── AS_QQ@2x.png │ │ │ └── Contents.json │ │ ├── dynamic_love.imageset │ │ │ ├── dynamic_love@2x.png │ │ │ └── Contents.json │ │ ├── header_wechat.imageset │ │ │ ├── AppIcon57x57@2x.png │ │ │ └── Contents.json │ │ ├── tab_oa_click.imageset │ │ │ ├── tab_oa_click@2x.png │ │ │ ├── tab_oa_click@3x.png │ │ │ └── Contents.json │ │ ├── chat_send_nor.imageset │ │ │ ├── chat_send_nor@2x.png │ │ │ └── Contents.json │ │ ├── chat_recive_nor.imageset │ │ │ ├── chat_recive_nor@2x.png │ │ │ └── Contents.json │ │ ├── dynamic_collect.imageset │ │ │ ├── dynamic_collect@2x.png │ │ │ └── Contents.json │ │ ├── dynamic_comment.imageset │ │ │ ├── dynamic_comment@2x.png │ │ │ └── Contents.json │ │ ├── tab_conversation.imageset │ │ │ ├── tab_conversation@2x.png │ │ │ ├── tab_conversation@3x.png │ │ │ └── Contents.json │ │ ├── dynamic_love_blue.imageset │ │ │ ├── dynamic_love_blue@2x.png │ │ │ └── Contents.json │ │ ├── emotion_btbg.imageset │ │ │ ├── chatgroup_emotion_btbg@2x.png │ │ │ └── Contents.json │ │ ├── chat_send_press_pic.imageset │ │ │ ├── chat_send_press_pic@2x.png │ │ │ └── Contents.json │ │ ├── dynamic_love_select.imageset │ │ │ ├── dynamic_love_select@2x.png │ │ │ └── Contents.json │ │ ├── chat_recive_press_pic.imageset │ │ │ ├── chat_recive_press_pic@2x.png │ │ │ └── Contents.json │ │ ├── dynamic_collect_select.imageset │ │ │ ├── dynamic_collect_select@2x.png │ │ │ └── Contents.json │ │ ├── dynamic_comment_select.imageset │ │ │ ├── dynamic_comment_select@2x.png │ │ │ └── Contents.json │ │ ├── tab_conversation_click.imageset │ │ │ ├── tab_conversation_click@2x.png │ │ │ ├── tab_conversation_click@3x.png │ │ │ └── Contents.json │ │ └── emoticon_keyboard_magnifier.imageset │ │ │ ├── emoticon_keyboard_magnifier@2x.png │ │ │ └── Contents.json │ └── AppIcon.appiconset │ │ └── Contents.json ├── OpenSources │ └── FMDB │ │ ├── FMDB.h │ │ ├── FMDatabasePool.h │ │ ├── FMDatabaseQueue.h │ │ ├── FMDatabaseQueue.m │ │ ├── FMDatabaseAdditions.m │ │ ├── FMDatabasePool.m │ │ ├── FMDatabaseAdditions.h │ │ ├── FMResultSet.m │ │ └── FMResultSet.h ├── Discover │ ├── Models │ │ ├── Dynamic.m │ │ └── Dynamic.h │ ├── Controllers │ │ ├── DynamicViewController.h │ │ └── DynamicViewController.m │ └── Views │ │ ├── DynamicView.h │ │ ├── DynamicCell.h │ │ ├── DynamicView.m │ │ └── DynamicCell.m ├── Chat │ ├── Models │ │ ├── ChatMessage.m │ │ └── ChatMessage.h │ ├── Controllers │ │ ├── ChatViewController.h │ │ ├── TextAndPictureViewController.h │ │ ├── TextAndPictureViewController.m │ │ └── ChatViewController.m │ └── Views │ │ ├── ChatCell.h │ │ ├── YYFaceView.h │ │ ├── YYFaceScrollView.h │ │ ├── YYFaceScrollView.m │ │ ├── YYFaceView.m │ │ └── ChatCell.m ├── AppDelegate.h ├── Utils │ ├── UIImage+Extension.h │ ├── JKDBHelper.h │ ├── UIImage+Extension.m │ ├── UIViewExt.h │ ├── Utility.h │ ├── JKDBHelper.m │ ├── JKDBModel.h │ ├── UIViewExt.m │ └── Utility.m ├── main.m ├── AppDelegate.m ├── TextUtil-Prefix.pch ├── Info.plist ├── emoticons.plist └── Base.lproj │ └── LaunchScreen.xib ├── TextUtil.xcodeproj ├── xcuserdata │ └── zx_04.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ └── TextUtil.xcscheme └── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcuserdata │ └── zx_04.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ └── xcshareddata │ └── TextUtil.xccheckout ├── README.md └── TextUtilTests ├── Info.plist └── TextUtilTests.m /TextUtil/Images/001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/001.png -------------------------------------------------------------------------------- /TextUtil/Images/002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/002.png -------------------------------------------------------------------------------- /TextUtil/Images/003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/003.png -------------------------------------------------------------------------------- /TextUtil/Images/004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/004.png -------------------------------------------------------------------------------- /TextUtil/Images/005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/005.png -------------------------------------------------------------------------------- /TextUtil/Images/006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/006.png -------------------------------------------------------------------------------- /TextUtil/Images/007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/007.png -------------------------------------------------------------------------------- /TextUtil/Images/008.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/008.png -------------------------------------------------------------------------------- /TextUtil/Images/009.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/009.png -------------------------------------------------------------------------------- /TextUtil/Images/010.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/010.png -------------------------------------------------------------------------------- /TextUtil/Images/011.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/011.png -------------------------------------------------------------------------------- /TextUtil/Images/012.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/012.png -------------------------------------------------------------------------------- /TextUtil/Images/013.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/013.png -------------------------------------------------------------------------------- /TextUtil/Images/014.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/014.png -------------------------------------------------------------------------------- /TextUtil/Images/015.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/015.png -------------------------------------------------------------------------------- /TextUtil/Images/016.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/016.png -------------------------------------------------------------------------------- /TextUtil/Images/017.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/017.png -------------------------------------------------------------------------------- /TextUtil/Images/018.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/018.png -------------------------------------------------------------------------------- /TextUtil/Images/019.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/019.png -------------------------------------------------------------------------------- /TextUtil/Images/020.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/020.png -------------------------------------------------------------------------------- /TextUtil/Images/021@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/021@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/022@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/022@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/023@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/023@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/024@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/024@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/025@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/025@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/026@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/026@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/027@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/027@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/028@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/028@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/029@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/029@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/030@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/030@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/031@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/031@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/032@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/032@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/033@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/033@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/034@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/034@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/035@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/035@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/036@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/036@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/037@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/037@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/038@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/038@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/039@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/039@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/040@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/040@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/041@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/041@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/042@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/042@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/043@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/043@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/044@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/044@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/045@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/045@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/046@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/046@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/047@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/047@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/048@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/048@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/049@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/049@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/050@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/050@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/051@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/051@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/052@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/052@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/053@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/053@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/054@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/054@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/055@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/055@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/056@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/056@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/057@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/057@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/058@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/058@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/059@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/059@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/060@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/060@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/061@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/061@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/062@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/062@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/063@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/063@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/064@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/064@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/065@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/065@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/066@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/066@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/067@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/067@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/068@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/068@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/069@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/069@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/070@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/070@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/071@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/071@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/072@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/072@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/073@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/073@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/074@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/074@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/075@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/075@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/076@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/076@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/077@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/077@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/078@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/078@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/079@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/079@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/080@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/080@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/081@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/081@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/082@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/082@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/083@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/083@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/084@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/084@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/085@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/085@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/086@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/086@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/087@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/087@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/088@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/088@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/089@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/089@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/090@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/090@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/091@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/091@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/092@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/092@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/093@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/093@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/094@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/094@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/095@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/095@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/096@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/096@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/097@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/097@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/098@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/098@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/099@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/099@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/100@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/100@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/101@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/101@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/102@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/102@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/103@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/103@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/104@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/104@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/105@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/105@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/image_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/image_01.jpg -------------------------------------------------------------------------------- /TextUtil/Images/image_02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/image_02.jpg -------------------------------------------------------------------------------- /TextUtil/Images/image_03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/image_03.jpg -------------------------------------------------------------------------------- /TextUtil/Images/image_04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/image_04.jpg -------------------------------------------------------------------------------- /TextUtil/Images/image_05.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/image_05.jpg -------------------------------------------------------------------------------- /TextUtil/Images/image_06.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/image_06.jpg -------------------------------------------------------------------------------- /TextUtil/Images/image_07.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/image_07.jpg -------------------------------------------------------------------------------- /TextUtil/Images/image_08.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/image_08.jpg -------------------------------------------------------------------------------- /TextUtil/Images/image_09.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/image_09.jpg -------------------------------------------------------------------------------- /TextUtil/Images/emotion@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/emotion@2x.png -------------------------------------------------------------------------------- /TextUtil/Images/ScreenShot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/ScreenShot1.png -------------------------------------------------------------------------------- /TextUtil/Images/ScreenShot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/ScreenShot2.png -------------------------------------------------------------------------------- /TextUtil/Images/ScreenShot3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images/ScreenShot3.png -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/tab_oa.imageset/tab_oa@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images.xcassets/image/tab_oa.imageset/tab_oa@2x.png -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/tab_oa.imageset/tab_oa@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images.xcassets/image/tab_oa.imageset/tab_oa@3x.png -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/header_QQ.imageset/AS_QQ@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images.xcassets/image/header_QQ.imageset/AS_QQ@2x.png -------------------------------------------------------------------------------- /TextUtil/OpenSources/FMDB/FMDB.h: -------------------------------------------------------------------------------- 1 | #import "FMDatabase.h" 2 | #import "FMResultSet.h" 3 | #import "FMDatabaseAdditions.h" 4 | #import "FMDatabaseQueue.h" 5 | #import "FMDatabasePool.h" 6 | -------------------------------------------------------------------------------- /TextUtil.xcodeproj/xcuserdata/zx_04.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/dynamic_love.imageset/dynamic_love@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images.xcassets/image/dynamic_love.imageset/dynamic_love@2x.png -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/header_wechat.imageset/AppIcon57x57@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images.xcassets/image/header_wechat.imageset/AppIcon57x57@2x.png -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/tab_oa_click.imageset/tab_oa_click@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images.xcassets/image/tab_oa_click.imageset/tab_oa_click@2x.png -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/tab_oa_click.imageset/tab_oa_click@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images.xcassets/image/tab_oa_click.imageset/tab_oa_click@3x.png -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/chat_send_nor.imageset/chat_send_nor@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images.xcassets/image/chat_send_nor.imageset/chat_send_nor@2x.png -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/chat_recive_nor.imageset/chat_recive_nor@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images.xcassets/image/chat_recive_nor.imageset/chat_recive_nor@2x.png -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/dynamic_collect.imageset/dynamic_collect@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images.xcassets/image/dynamic_collect.imageset/dynamic_collect@2x.png -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/dynamic_comment.imageset/dynamic_comment@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images.xcassets/image/dynamic_comment.imageset/dynamic_comment@2x.png -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/tab_conversation.imageset/tab_conversation@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images.xcassets/image/tab_conversation.imageset/tab_conversation@2x.png -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/tab_conversation.imageset/tab_conversation@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images.xcassets/image/tab_conversation.imageset/tab_conversation@3x.png -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/dynamic_love_blue.imageset/dynamic_love_blue@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images.xcassets/image/dynamic_love_blue.imageset/dynamic_love_blue@2x.png -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/emotion_btbg.imageset/chatgroup_emotion_btbg@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images.xcassets/image/emotion_btbg.imageset/chatgroup_emotion_btbg@2x.png -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/chat_send_press_pic.imageset/chat_send_press_pic@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images.xcassets/image/chat_send_press_pic.imageset/chat_send_press_pic@2x.png -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/dynamic_love_select.imageset/dynamic_love_select@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images.xcassets/image/dynamic_love_select.imageset/dynamic_love_select@2x.png -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/chat_recive_press_pic.imageset/chat_recive_press_pic@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images.xcassets/image/chat_recive_press_pic.imageset/chat_recive_press_pic@2x.png -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/dynamic_collect_select.imageset/dynamic_collect_select@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images.xcassets/image/dynamic_collect_select.imageset/dynamic_collect_select@2x.png -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/dynamic_comment_select.imageset/dynamic_comment_select@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images.xcassets/image/dynamic_comment_select.imageset/dynamic_comment_select@2x.png -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/tab_conversation_click.imageset/tab_conversation_click@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images.xcassets/image/tab_conversation_click.imageset/tab_conversation_click@2x.png -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/tab_conversation_click.imageset/tab_conversation_click@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images.xcassets/image/tab_conversation_click.imageset/tab_conversation_click@3x.png -------------------------------------------------------------------------------- /TextUtil.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TextUtil.xcodeproj/project.xcworkspace/xcuserdata/zx_04.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil.xcodeproj/project.xcworkspace/xcuserdata/zx_04.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/emoticon_keyboard_magnifier.imageset/emoticon_keyboard_magnifier@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xhellohaley/TextUtil/HEAD/TextUtil/Images.xcassets/image/emoticon_keyboard_magnifier.imageset/emoticon_keyboard_magnifier@2x.png -------------------------------------------------------------------------------- /TextUtil/Discover/Models/Dynamic.m: -------------------------------------------------------------------------------- 1 | // 2 | // Dynamic.m 3 | // TextUtil 4 | // 5 | // Created by zx_04 on 15/8/19. 6 | // Copyright (c) 2015年 joker. All rights reserved. 7 | // 8 | 9 | #import "Dynamic.h" 10 | 11 | @implementation Dynamic 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /TextUtil/Chat/Models/ChatMessage.m: -------------------------------------------------------------------------------- 1 | // 2 | // ChatMessage.m 3 | // TextUtil 4 | // 5 | // Created by zx_04 on 15/8/19. 6 | // Copyright (c) 2015年 joker. All rights reserved. 7 | // 8 | 9 | #import "ChatMessage.h" 10 | 11 | @implementation ChatMessage 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /TextUtil/Chat/Controllers/ChatViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ChatViewController.h 3 | // TextUtil 4 | // 5 | // Created by zx_04 on 15/8/19. 6 | // Copyright (c) 2015年 joker. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ChatViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /TextUtil/Discover/Controllers/DynamicViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DynamicViewController.h 3 | // TextUtil 4 | // 5 | // Created by zx_04 on 15/8/19. 6 | // Copyright (c) 2015年 joker. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DynamicViewController : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /TextUtil/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // TextUtil 4 | // 5 | // Created by zx_04 on 15/8/18. 6 | // Copyright (c) 2015年 joker. 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 | -------------------------------------------------------------------------------- /TextUtil/Utils/UIImage+Extension.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+Extension.h 3 | // TextUtil 4 | // 5 | // Created by zx_04 on 15/8/20. 6 | // Copyright (c) 2015年 joker. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIImage (Extension) 12 | 13 | // 图片拉伸 14 | + (UIImage *)resizableImageWithName:(NSString *)imageName; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /TextUtil/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // TextUtil 4 | // 5 | // Created by zx_04 on 15/8/18. 6 | // Copyright (c) 2015年 joker. 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 | -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/header_QQ.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "AS_QQ@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /TextUtil/Utils/JKDBHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // JKDataBase.h 3 | // JKBaseModel 4 | // 5 | // github:https://github.com/Joker-King/JKDBModel 6 | // Created by zx_04 on 15/6/24. 7 | // 8 | // 9 | 10 | #import 11 | #import "FMDB.h" 12 | 13 | @interface JKDBHelper : NSObject 14 | 15 | @property (nonatomic, retain, readonly) FMDatabaseQueue *dbQueue; 16 | 17 | + (JKDBHelper *)shareInstance; 18 | 19 | + (NSString *)dbPath; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TextUtil 2 | 一个工具类帮你三行代码实现图文混排功能。 3 | # 项目截图 4 | ![image](https://github.com/Joker-King/TextUtil/blob/master/TextUtil/Images/ScreenShot1.png) 5 | ![image](https://github.com/Joker-King/TextUtil/blob/master/TextUtil/Images/ScreenShot2.png) 6 | ![image](https://github.com/Joker-King/TextUtil/blob/master/TextUtil/Images/ScreenShot3.png) 7 | 8 | # 说明 9 | 项目中使用的表情图片是从其他地方拷贝出来的,尺寸大小不是很合适,原本都是@2x的,因为发送出来太小了,所以修改成了1倍图,如果要完整显示所有表情,修改图片名,去掉@2x,然后添加完全plist文件。 10 | -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/chat_send_nor.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "chat_send_nor@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/dynamic_love.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "dynamic_love@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/header_wechat.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "AppIcon57x57@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /TextUtil/Chat/Controllers/TextAndPictureViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TextAndPictureViewController.h 3 | // TextUtil 4 | // 5 | // Created by zx_04 on 15/8/24. 6 | // Copyright (c) 2015年 joker. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TextAndPictureViewController : UIViewController 12 | 13 | @property (weak, nonatomic) IBOutlet UILabel *firstLabel; 14 | @property (weak, nonatomic) IBOutlet UILabel *secondLabel; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/chat_recive_nor.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "chat_recive_nor@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/dynamic_collect.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "dynamic_collect@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/dynamic_comment.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "dynamic_comment@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/chat_send_press_pic.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "chat_send_press_pic@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/dynamic_love_blue.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "dynamic_love_blue@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/dynamic_love_select.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "dynamic_love_select@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/emotion_btbg.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "chatgroup_emotion_btbg@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/chat_recive_press_pic.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "chat_recive_press_pic@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/dynamic_collect_select.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "dynamic_collect_select@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/dynamic_comment_select.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "dynamic_comment_select@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/tab_oa.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "tab_oa@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x", 15 | "filename" : "tab_oa@3x.png" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/emoticon_keyboard_magnifier.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "emoticon_keyboard_magnifier@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/tab_oa_click.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "tab_oa_click@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x", 15 | "filename" : "tab_oa_click@3x.png" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/tab_conversation.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "tab_conversation@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x", 15 | "filename" : "tab_conversation@3x.png" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /TextUtil/Chat/Views/ChatCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // ChatCell.h 3 | // TextUtil 4 | // 5 | // Created by zx_04 on 15/8/19. 6 | // Copyright (c) 2015年 joker. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class ChatMessage; 12 | @interface ChatCell : UITableViewCell 13 | 14 | @property (nonatomic, retain) ChatMessage *message; 15 | 16 | + (instancetype)cellWithTableView:(UITableView *)tableView; 17 | 18 | /** 计算cell 的高度 */ 19 | + (CGFloat)heightOfCellWithMessage:(ChatMessage *)message; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /TextUtil/Images.xcassets/image/tab_conversation_click.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "tab_conversation_click@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x", 15 | "filename" : "tab_conversation_click@3x.png" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /TextUtil/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // TextUtil 4 | // 5 | // Created by zx_04 on 15/8/18. 6 | // Copyright (c) 2015年 joker. 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 | 24 | @end 25 | -------------------------------------------------------------------------------- /TextUtil/Chat/Views/YYFaceView.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYFaceView.h 3 | // 4 | // 5 | // Created by Joker on 14-1-6. 6 | // Copyright (c) 2014年 Mac. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef void(^SelectBlock) (NSString *faceName); 12 | 13 | @interface YYFaceView : UIView 14 | { 15 | NSMutableArray *items; 16 | UIImageView *magnifierView; 17 | } 18 | 19 | @property (nonatomic,copy) NSString *selectedFaceName; 20 | @property (nonatomic,assign) NSInteger pageNumber; 21 | @property (nonatomic,copy) SelectBlock block; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /TextUtil/Chat/Models/ChatMessage.h: -------------------------------------------------------------------------------- 1 | // 2 | // ChatMessage.h 3 | // TextUtil 4 | // 5 | // Created by zx_04 on 15/8/19. 6 | // Copyright (c) 2015年 joker. All rights reserved. 7 | // 8 | 9 | #import "JKDBModel.h" 10 | 11 | typedef enum : NSUInteger { 12 | MessageTypeText, 13 | MessageTypeAudio, 14 | MessageTypePicture, 15 | MessageTypeVideo, 16 | } MessageType; 17 | 18 | @interface ChatMessage : JKDBModel 19 | 20 | @property (nonatomic, copy) NSString *content; 21 | @property (nonatomic, assign) MessageType messageType; 22 | @property (nonatomic, assign) BOOL isSender; 23 | 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /TextUtil/Chat/Views/YYFaceScrollView.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYFaceScrollView.h 3 | // ismarter2.0_sz 4 | // 5 | // Created by zx_04 on 15/6/15. 6 | // 7 | // 8 | 9 | #import 10 | #import "YYFaceView.h" 11 | 12 | typedef void(^SendBtnClickBlock)(void); 13 | 14 | @interface YYFaceScrollView : UIView 15 | { 16 | UIScrollView *scrollView; 17 | YYFaceView *faceView; 18 | UIPageControl *pageControl; 19 | UIView *bottomView; 20 | } 21 | 22 | @property (nonatomic, copy) SendBtnClickBlock sendBlock; 23 | 24 | - (id)initWithSelectBlock:(SelectBlock)block; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /TextUtil.xcodeproj/xcuserdata/zx_04.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | TextUtil.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 6B40A5731B833B1F00A46C7C 16 | 17 | primary 18 | 19 | 20 | 6B40A58C1B833B1F00A46C7C 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /TextUtil/Discover/Views/DynamicView.h: -------------------------------------------------------------------------------- 1 | // 2 | // DynamicView.h 3 | // TextUtil 4 | // 5 | // Created by zx_04 on 15/8/19. 6 | // Copyright (c) 2015年 joker. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "Dynamic.h" 12 | 13 | #define kContentFont [UIFont systemFontOfSize:15.0] //正文字体 14 | #define kDynamicWidth (kWidth-65-10) //内容视图宽度 15 | #define kImagePadding 5 //图片间距 16 | #define kImageWidth (kDynamicWidth-kImagePadding*2)/3 //图片宽度 17 | 18 | #define kSingleImageWidth 200 //单张图片的宽度 19 | 20 | @interface DynamicView : UIView 21 | 22 | @property (nonatomic, retain) Dynamic *dynamic; 23 | 24 | + (CGFloat)getHeightWithModel:(Dynamic *)dynamic; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /TextUtil/Discover/Views/DynamicCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // DynamicCell.h 3 | // TextUtil 4 | // 5 | // Created by zx_04 on 15/8/19. 6 | // Copyright (c) 2015年 joker. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #define nameColor RGBColor(50, 85, 140, 1.0) //名字颜色 12 | #define customGrayColor RGBColor(175, 180, 200, 1.0) //灰色 13 | #define kFaceWidth 45 //头像视图的宽、高 14 | #define kOptionHeight 30 //操作视图的高度 15 | #define kPadding 10 //视图之间的间距 16 | 17 | @class Dynamic; 18 | @interface DynamicCell : UITableViewCell 19 | 20 | /** 朋友圈信息实体 */ 21 | @property (nonatomic, retain) Dynamic *dynamic; 22 | 23 | + (DynamicCell *)cellWithTableView:(UITableView *)tableView; 24 | 25 | + (CGFloat)heightOfCellWithModel:(Dynamic *)dynamic; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /TextUtil/Images.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 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /TextUtil/Discover/Models/Dynamic.h: -------------------------------------------------------------------------------- 1 | // 2 | // Dynamic.h 3 | // TextUtil 4 | // 5 | // Created by zx_04 on 15/8/19. 6 | // Copyright (c) 2015年 joker. All rights reserved. 7 | // 8 | 9 | #import "JKDBModel.h" 10 | 11 | @interface Dynamic : JKDBModel 12 | 13 | @property (nonatomic, assign) BOOL isPraise; 14 | @property (nonatomic, assign) int praiseCount; 15 | @property (nonatomic, copy) NSString *location; 16 | @property (nonatomic, copy) NSString *createTime; 17 | /** 类型含义:0:纯文字 1:带图片(文字+图片/纯图片) 2:带视频(文字+视频/纯视频) */ 18 | @property (nonatomic, assign) int type; 19 | @property (nonatomic, copy) NSString *text; 20 | @property (nonatomic, assign) int imageCount; 21 | @property (nonatomic, assign) int replyCount; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /TextUtil/Utils/UIImage+Extension.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+Extension.m 3 | // TextUtil 4 | // 5 | // Created by zx_04 on 15/8/20. 6 | // Copyright (c) 2015年 joker. All rights reserved. 7 | // 8 | 9 | #import "UIImage+Extension.h" 10 | 11 | @implementation UIImage (Extension) 12 | 13 | + (UIImage *)resizableImageWithName:(NSString *)imageName 14 | { 15 | 16 | // 加载原有图片 17 | UIImage *norImage = [UIImage imageNamed:imageName]; 18 | // 获取原有图片的宽高的一半 19 | CGFloat w = norImage.size.width * 0.5; 20 | CGFloat top = norImage.size.height * 0.5; 21 | CGFloat bottom = norImage.size.height-top; 22 | // 生成可以拉伸指定位置的图片 23 | UIImage *newImage = [norImage resizableImageWithCapInsets:UIEdgeInsetsMake(top, w, bottom, w) resizingMode:UIImageResizingModeStretch]; 24 | 25 | return newImage; 26 | } 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /TextUtilTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.zx.$(PRODUCT_NAME:rfc1034identifier) 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 | -------------------------------------------------------------------------------- /TextUtil/Utils/UIViewExt.h: -------------------------------------------------------------------------------- 1 | /* 2 | Erica Sadun, http://ericasadun.com 3 | iPhone Developer's Cookbook, 3.0 Edition 4 | BSD License, Use at your own risk 5 | */ 6 | 7 | #import 8 | 9 | CGPoint CGRectGetCenter(CGRect rect); 10 | CGRect CGRectMoveToCenter(CGRect rect, CGPoint center); 11 | 12 | @interface UIView (ViewFrameGeometry) 13 | @property CGPoint origin; 14 | @property CGSize size; 15 | 16 | @property (readonly) CGPoint bottomLeft; 17 | @property (readonly) CGPoint bottomRight; 18 | @property (readonly) CGPoint topRight; 19 | 20 | @property CGFloat height; 21 | @property CGFloat width; 22 | 23 | @property CGFloat top; 24 | @property CGFloat left; 25 | 26 | @property CGFloat bottom; 27 | @property CGFloat right; 28 | 29 | - (void) moveBy: (CGPoint) delta; 30 | - (void) scaleBy: (CGFloat) scaleFactor; 31 | - (void) fitInSize: (CGSize) aSize; 32 | - (UIViewController *)viewController; 33 | 34 | 35 | @end -------------------------------------------------------------------------------- /TextUtil/Utils/Utility.h: -------------------------------------------------------------------------------- 1 | // 2 | // Utility.h 3 | // TextUtil 4 | // 5 | // Created by zx_04 on 15/8/20. 6 | // Copyright (c) 2015年 joker. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface Utility : NSObject 12 | 13 | //处理表情字符 14 | + (NSMutableAttributedString *)emotionStrWithString:(NSString *)text; 15 | 16 | /** 17 | * 将带有表情符的文字转换为图文混排的文字 18 | * 19 | * @param text 带表情符的文字 20 | * @param plistName 表情符与表情对应的plist文件 21 | * @param y 图片的y偏移值 22 | * 23 | * @return 转换后的文字 24 | */ 25 | + (NSMutableAttributedString *)emotionStrWithString:(NSString *)text plistName:(NSString *)plistName y:(CGFloat)y; 26 | /** 27 | * 将个别文字转换为特殊的图片 28 | * 29 | * @param string 原始文字段落 30 | * @param text 特殊的文字 31 | * @param imageName 要替换的图片 32 | * 33 | * @return NSMutableAttributedString 34 | */ 35 | + (NSMutableAttributedString *)exchangeString:(NSString *)string withText:(NSString *)text imageName:(NSString *)imageName; 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /TextUtilTests/TextUtilTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // TextUtilTests.m 3 | // TextUtilTests 4 | // 5 | // Created by zx_04 on 15/8/18. 6 | // Copyright (c) 2015年 joker. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface TextUtilTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation TextUtilTests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | XCTAssert(YES, @"Pass"); 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /TextUtil/Chat/Controllers/TextAndPictureViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TextAndPictureViewController.m 3 | // TextUtil 4 | // 5 | // Created by zx_04 on 15/8/24. 6 | // Copyright (c) 2015年 joker. All rights reserved. 7 | // 8 | 9 | #import "TextAndPictureViewController.h" 10 | 11 | #import "Utility.h" 12 | 13 | @interface TextAndPictureViewController () 14 | 15 | @end 16 | 17 | @implementation TextAndPictureViewController 18 | 19 | - (void)viewDidLoad { 20 | [super viewDidLoad]; 21 | // Do any additional setup after loading the view. 22 | 23 | NSString *content = @"文字加上表情[得意][酷][呲牙]"; 24 | NSMutableAttributedString *attrStr = [Utility emotionStrWithString:content]; 25 | _firstLabel.attributedText= attrStr; 26 | 27 | NSString *text = @"<微信>腾讯科技讯 微软提供免费升级的Windows 10,在全球获得普遍好评。但微软已经有一段时间没有公布最新升级数据。科技市场研究公司StatCounter发布了有关Windows升级的相关数据,显示出Windows 10的升级节奏开始放缓。<微信>另外,数据显示Windows 8用户是升级的主力军,Windows 7用户升级动力不太足。"; 28 | NSMutableAttributedString *attrStr2 = [Utility exchangeString:@"<微信>" withText:text imageName:@"header_wechat"]; 29 | _secondLabel.attributedText = attrStr2; 30 | 31 | } 32 | 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /TextUtil/TextUtil-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // TextUtil-Prefix.pch 3 | // TextUtil 4 | // 5 | // Created by zx_04 on 15/8/19. 6 | // Copyright (c) 2015年 joker. All rights reserved. 7 | // 8 | 9 | #ifndef TextUtil_TextUtil_Prefix_pch 10 | #define TextUtil_TextUtil_Prefix_pch 11 | 12 | #ifdef __OBJC__ 13 | #import 14 | #import 15 | 16 | #import "JKDBModel.h" 17 | #import "UIViewExt.h" 18 | #endif 19 | 20 | #ifdef DEBUG 21 | #define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__) 22 | #else 23 | #define DLog(fmt, ...) nil 24 | #endif 25 | 26 | #define kWidth [UIScreen mainScreen].bounds.size.width //获取设备的物理宽度 27 | #define kHeight [UIScreen mainScreen].bounds.size.height //获取设备的物理高度 28 | 29 | /****************************** 颜色 ********************************/ 30 | #define RGBColor(r,g,b,a) ([UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a]) 31 | /** tableView 边框颜色 */ 32 | #define TABLEVIEW_BORDER_COLOR RGBColor(230, 230, 230, 1) 33 | /**所有控制的背景色 */ 34 | #define VIEW_BGCOLOR RGBColor(240, 240, 240, 1) 35 | #define cellBlackColor RGBColor(235, 235, 245, 0.7) 36 | 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /TextUtil/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.zx.$(PRODUCT_NAME:rfc1034identifier) 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 | 38 | 39 | -------------------------------------------------------------------------------- /TextUtil.xcodeproj/project.xcworkspace/xcshareddata/TextUtil.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 101B3700-9C04-4E75-B857-68F594AEAA53 9 | IDESourceControlProjectName 10 | TextUtil 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | C2A3E10B52AE52188240D6161EBF206ED93970DE 14 | https://github.com/Joker-King/TextUtil.git 15 | 16 | IDESourceControlProjectPath 17 | TextUtil.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | C2A3E10B52AE52188240D6161EBF206ED93970DE 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/Joker-King/TextUtil.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | C2A3E10B52AE52188240D6161EBF206ED93970DE 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | C2A3E10B52AE52188240D6161EBF206ED93970DE 36 | IDESourceControlWCCName 37 | TextUtil 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /TextUtil/Utils/JKDBHelper.m: -------------------------------------------------------------------------------- 1 | // 2 | // JKDataBase.m 3 | // JKBaseModel 4 | // 5 | // github:https://github.com/Joker-King/JKDBModel 6 | // Created by zx_04 on 15/6/24. 7 | // 8 | // 9 | 10 | #import "JKDBHelper.h" 11 | 12 | @interface JKDBHelper () 13 | 14 | @property (nonatomic, retain) FMDatabaseQueue *dbQueue; 15 | 16 | @end 17 | 18 | @implementation JKDBHelper 19 | 20 | static JKDBHelper *_instance = nil; 21 | 22 | + (instancetype)shareInstance 23 | { 24 | static dispatch_once_t onceToken ; 25 | dispatch_once(&onceToken, ^{ 26 | _instance = [[super allocWithZone:NULL] init] ; 27 | }) ; 28 | 29 | return _instance; 30 | } 31 | 32 | + (NSString *)dbPath 33 | { 34 | NSString *docsdir = [NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; 35 | NSFileManager *filemanage = [NSFileManager defaultManager]; 36 | docsdir = [docsdir stringByAppendingPathComponent:@"JKBD"]; 37 | BOOL isDir; 38 | BOOL exit =[filemanage fileExistsAtPath:docsdir isDirectory:&isDir]; 39 | if (!exit || !isDir) { 40 | [filemanage createDirectoryAtPath:docsdir withIntermediateDirectories:YES attributes:nil error:nil]; 41 | } 42 | NSString *dbpath = [docsdir stringByAppendingPathComponent:@"jkdb.sqlite"]; 43 | return dbpath; 44 | } 45 | 46 | - (FMDatabaseQueue *)dbQueue 47 | { 48 | if (_dbQueue == nil) { 49 | _dbQueue = [[FMDatabaseQueue alloc] initWithPath:[self.class dbPath]]; 50 | } 51 | return _dbQueue; 52 | } 53 | 54 | + (id)allocWithZone:(struct _NSZone *)zone 55 | { 56 | return [JKDBHelper shareInstance]; 57 | } 58 | 59 | - (id)copyWithZone:(struct _NSZone *)zone 60 | { 61 | return [JKDBHelper shareInstance]; 62 | } 63 | 64 | #if ! __has_feature(objc_arc) 65 | - (oneway void)release 66 | { 67 | 68 | } 69 | 70 | - (id)autorelease 71 | { 72 | return _instance; 73 | } 74 | 75 | - (NSUInteger)retainCount 76 | { 77 | return 1; 78 | } 79 | #endif 80 | 81 | @end 82 | -------------------------------------------------------------------------------- /TextUtil/Utils/JKDBModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // JKBaseModel.h 3 | // JKBaseModel 4 | // 5 | // github:https://github.com/Joker-King/JKDBModel 6 | // Created by zx_04 on 15/6/27. 7 | // Copyright (c) 2015年 joker. All rights reserved. 8 | // 9 | 10 | #import 11 | 12 | #import "JKDBHelper.h" 13 | 14 | /** SQLite五种数据类型 */ 15 | #define SQLTEXT @"TEXT" 16 | #define SQLINTEGER @"INTEGER" 17 | #define SQLREAL @"REAL" 18 | #define SQLBLOB @"BLOB" 19 | #define SQLNULL @"NULL" 20 | #define PrimaryKey @"primary key" 21 | 22 | #define primaryId @"pk" 23 | 24 | @interface JKDBModel : NSObject 25 | 26 | /** 主键 id */ 27 | @property (nonatomic, assign) int pk; 28 | /** 列名 */ 29 | @property (retain, readonly, nonatomic) NSMutableArray *columeNames; 30 | /** 列类型 */ 31 | @property (retain, readonly, nonatomic) NSMutableArray *columeTypes; 32 | 33 | /** 34 | * 获取该类的所有属性 35 | */ 36 | + (NSDictionary *)getPropertys; 37 | 38 | /** 获取所有属性,包括主键 */ 39 | + (NSDictionary *)getAllProperties; 40 | 41 | /** 数据库中是否存在表 */ 42 | + (BOOL)isExistInTable; 43 | 44 | /** 表中的字段*/ 45 | + (NSArray *)getColumns; 46 | 47 | /** 保存或更新 48 | * 如果不存在主键,保存, 49 | * 有主键,则更新 50 | */ 51 | - (BOOL)saveOrUpdate; 52 | /** 保存单个数据 */ 53 | - (BOOL)save; 54 | /** 批量保存数据 */ 55 | + (BOOL)saveObjects:(NSArray *)array; 56 | /** 更新单个数据 */ 57 | - (BOOL)update; 58 | /** 批量更新数据*/ 59 | + (BOOL)updateObjects:(NSArray *)array; 60 | /** 删除单个数据 */ 61 | - (BOOL)deleteObject; 62 | /** 批量删除数据 */ 63 | + (BOOL)deleteObjects:(NSArray *)array; 64 | /** 通过条件删除数据 */ 65 | + (BOOL)deleteObjectsByCriteria:(NSString *)criteria; 66 | /** 清空表 */ 67 | + (BOOL)clearTable; 68 | 69 | /** 查询全部数据 */ 70 | + (NSArray *)findAll; 71 | 72 | /** 通过主键查询 */ 73 | + (instancetype)findByPK:(int)inPk; 74 | 75 | /** 查找某条数据 */ 76 | + (instancetype)findFirstByCriteria:(NSString *)criteria; 77 | 78 | /** 通过条件查找数据 79 | * 这样可以进行分页查询 @" WHERE pk > 5 limit 10" 80 | */ 81 | + (NSArray *)findByCriteria:(NSString *)criteria; 82 | 83 | /** 获取最大值 */ 84 | + (int)getMaxOf:(NSString *)columeName; 85 | 86 | #pragma mark - must be override method 87 | /** 88 | * 创建表 89 | * 如果已经创建,返回YES 90 | */ 91 | + (BOOL)createTable; 92 | /** 如果子类中有一些property不需要创建数据库字段,那么这个方法必须在子类中重写 93 | */ 94 | + (NSArray *)transients; 95 | 96 | 97 | @end 98 | -------------------------------------------------------------------------------- /TextUtil/emoticons.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | cht 7 | [微笑] 8 | png 9 | 001 10 | 11 | 12 | cht 13 | [撇嘴] 14 | png 15 | 002 16 | 17 | 18 | cht 19 | [色] 20 | png 21 | 003 22 | 23 | 24 | cht 25 | [发呆] 26 | png 27 | 004 28 | 29 | 30 | cht 31 | [得意] 32 | png 33 | 005 34 | 35 | 36 | cht 37 | [流泪] 38 | png 39 | 006 40 | 41 | 42 | cht 43 | [害羞] 44 | png 45 | 007 46 | 47 | 48 | cht 49 | [闭嘴] 50 | png 51 | 008 52 | 53 | 54 | cht 55 | [睡] 56 | png 57 | 009 58 | 59 | 60 | cht 61 | [大哭] 62 | png 63 | 010 64 | 65 | 66 | cht 67 | [尴尬] 68 | png 69 | 011 70 | 71 | 72 | cht 73 | [发怒] 74 | png 75 | 012 76 | 77 | 78 | cht 79 | [调皮] 80 | png 81 | 013 82 | 83 | 84 | cht 85 | [呲牙] 86 | png 87 | 014 88 | 89 | 90 | cht 91 | [惊讶] 92 | png 93 | 015 94 | 95 | 96 | cht 97 | [难过] 98 | png 99 | 016 100 | 101 | 102 | cht 103 | [酷] 104 | png 105 | 017 106 | 107 | 108 | cht 109 | [冷汗] 110 | png 111 | 018 112 | 113 | 114 | cht 115 | [抓狂] 116 | png 117 | 019 118 | 119 | 120 | cht 121 | [吐] 122 | png 123 | 020 124 | 125 | 126 | cht 127 | [偷笑] 128 | png 129 | 021 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /TextUtil/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /TextUtil/Chat/Views/YYFaceScrollView.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYFaceScrollView.m 3 | // ismarter2.0_sz 4 | // 5 | // Created by zx_04 on 15/6/15. 6 | // 7 | // 8 | 9 | #import "YYFaceScrollView.h" 10 | 11 | @implementation YYFaceScrollView 12 | 13 | - (id)initWithFrame:(CGRect)frame 14 | { 15 | self = [super initWithFrame:frame]; 16 | if (self) { 17 | [self initViews]; 18 | } 19 | return self; 20 | } 21 | 22 | - (id)initWithSelectBlock:(SelectBlock)block 23 | { 24 | self = [self initWithFrame:CGRectZero]; 25 | if (self != nil) { 26 | faceView.block = block; 27 | } 28 | return self; 29 | } 30 | 31 | - (void)initViews 32 | { 33 | //顶部的分隔线 34 | UIView *topLineView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kWidth, 0.5)]; 35 | topLineView.backgroundColor = [UIColor grayColor]; 36 | topLineView.alpha = 0.3; 37 | [self addSubview:topLineView]; 38 | 39 | faceView = [[YYFaceView alloc] initWithFrame:CGRectZero]; 40 | 41 | scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, kWidth, faceView.height)]; 42 | scrollView.backgroundColor = [UIColor clearColor]; 43 | scrollView.contentSize = CGSizeMake(faceView.width, faceView.height); 44 | scrollView.pagingEnabled = YES; 45 | scrollView.showsHorizontalScrollIndicator = NO; 46 | scrollView.clipsToBounds = NO; 47 | scrollView.delegate = self; 48 | 49 | [scrollView addSubview:faceView]; 50 | [self addSubview:scrollView]; 51 | 52 | pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, scrollView.bottom, 40, 20)]; 53 | pageControl.backgroundColor = [UIColor clearColor]; 54 | pageControl.numberOfPages = faceView.pageNumber; 55 | pageControl.currentPage = 0; 56 | [self addSubview:pageControl]; 57 | 58 | [self addbottomView]; 59 | 60 | self.height = scrollView.height + pageControl.height + 10 +bottomView.height; 61 | self.width = scrollView.width; 62 | } 63 | 64 | - (void)addbottomView 65 | { 66 | // bottomView = [[UIView alloc] initWithFrame:CGRectMake(0, pageControl.bottom+10, 320, 35)]; 67 | bottomView = [[UIView alloc] initWithFrame:CGRectMake(0, pageControl.bottom+10, kWidth, 35)]; 68 | bottomView.backgroundColor = [UIColor clearColor]; 69 | [self addSubview:bottomView]; 70 | 71 | UIView *topLine =[[UIView alloc] initWithFrame:CGRectMake(0, 0, bottomView.width, 0.5)]; 72 | topLine.backgroundColor = [UIColor grayColor]; 73 | [bottomView addSubview:topLine]; 74 | 75 | UIButton *smallemoBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, bottomView.height, bottomView.height)]; 76 | smallemoBtn.backgroundColor = [UIColor clearColor]; 77 | [smallemoBtn setImage:[UIImage imageNamed:@"emotion"] forState:UIControlStateNormal]; 78 | [smallemoBtn addTarget:self action:@selector(changeForEmotion) forControlEvents:UIControlEventTouchUpInside]; 79 | [bottomView addSubview:smallemoBtn]; 80 | 81 | UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(smallemoBtn.right+2, 3, 1, smallemoBtn.height-6)]; 82 | lineView.backgroundColor = [UIColor grayColor]; 83 | [bottomView addSubview:lineView]; 84 | 85 | UIButton *sendBtn = [[UIButton alloc] initWithFrame:CGRectMake(kWidth-60, 0, 60, bottomView.height)]; 86 | sendBtn.backgroundColor = RGBColor(0, 122, 255, 1); 87 | [sendBtn setTitle:@"发送" forState:UIControlStateNormal]; 88 | [sendBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; 89 | [sendBtn addTarget:self action:@selector(sendBtnClick) forControlEvents:UIControlEventTouchUpInside]; 90 | [bottomView addSubview:sendBtn]; 91 | } 92 | 93 | - (void)scrollViewDidScroll:(UIScrollView *)_scrollView; 94 | { 95 | int pageNumber = _scrollView.contentOffset.x/320; 96 | pageControl.currentPage = pageNumber; 97 | } 98 | 99 | - (void)changeForEmotion 100 | { 101 | NSLog(@"%s",__func__); 102 | } 103 | 104 | - (void)sendBtnClick 105 | { 106 | NSLog(@"%s",__func__); 107 | if (_sendBlock) { 108 | _sendBlock(); 109 | } 110 | } 111 | 112 | @end 113 | -------------------------------------------------------------------------------- /TextUtil.xcodeproj/xcuserdata/zx_04.xcuserdatad/xcschemes/TextUtil.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 77 | 83 | 84 | 85 | 86 | 87 | 88 | 94 | 96 | 102 | 103 | 104 | 105 | 107 | 108 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /TextUtil/Utils/UIViewExt.m: -------------------------------------------------------------------------------- 1 | /* 2 | Erica Sadun, http://ericasadun.com 3 | iPhone Developer's Cookbook, 3.0 Edition 4 | BSD License, Use at your own risk 5 | */ 6 | 7 | #import "UIViewExt.h" 8 | 9 | CGPoint CGRectGetCenter(CGRect rect) 10 | { 11 | CGPoint pt; 12 | pt.x = CGRectGetMidX(rect); 13 | pt.y = CGRectGetMidY(rect); 14 | return pt; 15 | } 16 | 17 | CGRect CGRectMoveToCenter(CGRect rect, CGPoint center) 18 | { 19 | CGRect newrect = CGRectZero; 20 | newrect.origin.x = center.x-CGRectGetMidX(rect); 21 | newrect.origin.y = center.y-CGRectGetMidY(rect); 22 | newrect.size = rect.size; 23 | return newrect; 24 | } 25 | 26 | @implementation UIView (ViewGeometry) 27 | 28 | // Retrieve and set the origin 29 | - (CGPoint) origin 30 | { 31 | return self.frame.origin; 32 | } 33 | 34 | - (void) setOrigin: (CGPoint) aPoint 35 | { 36 | CGRect newframe = self.frame; 37 | newframe.origin = aPoint; 38 | self.frame = newframe; 39 | } 40 | 41 | 42 | // Retrieve and set the size 43 | - (CGSize) size 44 | { 45 | return self.frame.size; 46 | } 47 | 48 | - (void) setSize: (CGSize) aSize 49 | { 50 | CGRect newframe = self.frame; 51 | newframe.size = aSize; 52 | self.frame = newframe; 53 | } 54 | 55 | // Query other frame locations 56 | - (CGPoint) bottomRight 57 | { 58 | CGFloat x = self.frame.origin.x + self.frame.size.width; 59 | CGFloat y = self.frame.origin.y + self.frame.size.height; 60 | return CGPointMake(x, y); 61 | } 62 | 63 | - (CGPoint) bottomLeft 64 | { 65 | CGFloat x = self.frame.origin.x; 66 | CGFloat y = self.frame.origin.y + self.frame.size.height; 67 | return CGPointMake(x, y); 68 | } 69 | 70 | - (CGPoint) topRight 71 | { 72 | CGFloat x = self.frame.origin.x + self.frame.size.width; 73 | CGFloat y = self.frame.origin.y; 74 | return CGPointMake(x, y); 75 | } 76 | 77 | 78 | // Retrieve and set height, width, top, bottom, left, right 79 | - (CGFloat) height 80 | { 81 | return self.frame.size.height; 82 | } 83 | 84 | - (void) setHeight: (CGFloat) newheight 85 | { 86 | CGRect newframe = self.frame; 87 | newframe.size.height = newheight; 88 | self.frame = newframe; 89 | } 90 | 91 | - (CGFloat) width 92 | { 93 | return self.frame.size.width; 94 | } 95 | 96 | - (void) setWidth: (CGFloat) newwidth 97 | { 98 | CGRect newframe = self.frame; 99 | newframe.size.width = newwidth; 100 | self.frame = newframe; 101 | } 102 | 103 | - (CGFloat) top 104 | { 105 | return self.frame.origin.y; 106 | } 107 | 108 | - (void) setTop: (CGFloat) newtop 109 | { 110 | CGRect newframe = self.frame; 111 | newframe.origin.y = newtop; 112 | self.frame = newframe; 113 | } 114 | 115 | - (CGFloat) left 116 | { 117 | return self.frame.origin.x; 118 | } 119 | 120 | - (void) setLeft: (CGFloat) newleft 121 | { 122 | CGRect newframe = self.frame; 123 | newframe.origin.x = newleft; 124 | self.frame = newframe; 125 | } 126 | 127 | - (CGFloat) bottom 128 | { 129 | return self.frame.origin.y + self.frame.size.height; 130 | } 131 | 132 | - (void) setBottom: (CGFloat) newbottom 133 | { 134 | CGRect newframe = self.frame; 135 | newframe.origin.y = newbottom - self.frame.size.height; 136 | self.frame = newframe; 137 | } 138 | 139 | - (CGFloat) right 140 | { 141 | return self.frame.origin.x + self.frame.size.width; 142 | } 143 | 144 | - (void) setRight: (CGFloat) newright 145 | { 146 | CGFloat delta = newright - (self.frame.origin.x + self.frame.size.width); 147 | CGRect newframe = self.frame; 148 | newframe.origin.x += delta ; 149 | self.frame = newframe; 150 | } 151 | 152 | // Move via offset 153 | - (void) moveBy: (CGPoint) delta 154 | { 155 | CGPoint newcenter = self.center; 156 | newcenter.x += delta.x; 157 | newcenter.y += delta.y; 158 | self.center = newcenter; 159 | } 160 | 161 | // Scaling 162 | - (void) scaleBy: (CGFloat) scaleFactor 163 | { 164 | CGRect newframe = self.frame; 165 | newframe.size.width *= scaleFactor; 166 | newframe.size.height *= scaleFactor; 167 | self.frame = newframe; 168 | } 169 | 170 | // Ensure that both dimensions fit within the given size by scaling down 171 | - (void) fitInSize: (CGSize) aSize 172 | { 173 | CGFloat scale; 174 | CGRect newframe = self.frame; 175 | 176 | if (newframe.size.height && (newframe.size.height > aSize.height)) 177 | { 178 | scale = aSize.height / newframe.size.height; 179 | newframe.size.width *= scale; 180 | newframe.size.height *= scale; 181 | } 182 | 183 | if (newframe.size.width && (newframe.size.width >= aSize.width)) 184 | { 185 | scale = aSize.width / newframe.size.width; 186 | newframe.size.width *= scale; 187 | newframe.size.height *= scale; 188 | } 189 | 190 | self.frame = newframe; 191 | } 192 | 193 | - (UIViewController *)viewController 194 | { 195 | UIResponder *next = [self nextResponder]; 196 | do { 197 | if ([next isKindOfClass:[UIViewController class]]) { 198 | return (UIViewController *)next; 199 | } 200 | 201 | next = [next nextResponder]; 202 | 203 | } while (next != nil); 204 | 205 | 206 | return nil; 207 | } 208 | @end -------------------------------------------------------------------------------- /TextUtil/Discover/Controllers/DynamicViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // DynamicViewController.m 3 | // TextUtil 4 | // 5 | // Created by zx_04 on 15/8/19. 6 | // Copyright (c) 2015年 joker. All rights reserved. 7 | // 8 | 9 | #import "DynamicViewController.h" 10 | 11 | #import "DynamicCell.h" 12 | #import "Dynamic.h" 13 | 14 | @interface DynamicViewController () 15 | 16 | @property (nonatomic, strong) NSArray *dynamicData; 17 | 18 | @end 19 | 20 | @implementation DynamicViewController 21 | 22 | - (void)viewDidLoad { 23 | [super viewDidLoad]; 24 | 25 | [self loadDynamicData]; 26 | } 27 | 28 | - (void)loadDynamicData 29 | { 30 | 31 | Dynamic *dynamic = [[Dynamic alloc] init]; 32 | dynamic.isPraise = YES; 33 | dynamic.location = @"深圳市"; 34 | dynamic.createTime = @"12:50"; 35 | dynamic.type = 0; 36 | dynamic.text = @"山不在高,有仙则名。水不在深,有龙则灵。斯是陋室,惟吾德馨。苔痕上阶绿,草色入帘青。谈笑有鸿儒,往来无白丁。可以调素琴,阅金经。无丝竹之乱耳,无案牍之劳形。南阳诸葛庐,西蜀子云亭。孔子云:何陋之有?"; 37 | dynamic.imageCount = 0; 38 | dynamic.replyCount = 66; 39 | [dynamic save]; 40 | 41 | Dynamic *dynamic2 = [[Dynamic alloc] init]; 42 | dynamic2.isPraise = YES; 43 | dynamic2.location = @"上海"; 44 | dynamic2.createTime = @"昨天 10:11"; 45 | dynamic2.type = 1; 46 | dynamic2.text = nil; 47 | dynamic2.imageCount = 1; 48 | dynamic2.replyCount = 188; 49 | [dynamic2 save]; 50 | 51 | Dynamic *dynamic3 = [[Dynamic alloc] init]; 52 | dynamic3.isPraise = YES; 53 | dynamic3.location = @"北京市"; 54 | dynamic3.createTime = @"前天 10:11"; 55 | dynamic3.type = 1; 56 | dynamic3.text = @"人的一生可能燃烧也可能腐朽,我不能腐朽,我愿意燃烧起来!"; 57 | dynamic3.imageCount = 3; 58 | dynamic3.replyCount = 66; 59 | [dynamic3 save]; 60 | 61 | Dynamic *dynamic4 = [[Dynamic alloc] init]; 62 | dynamic4.isPraise = YES; 63 | dynamic4.location = @"北京市"; 64 | dynamic4.createTime = @"前天 10:11"; 65 | dynamic4.type = 1; 66 | dynamic4.text = @"夫君子之行,静以修身,俭以养德,非淡泊无以明志,非宁静无以致远"; 67 | dynamic4.imageCount = 9; 68 | dynamic4.replyCount = 211; 69 | [dynamic4 save]; 70 | 71 | dispatch_async(dispatch_get_global_queue(0, 0), ^{ 72 | NSArray *data = [Dynamic findAll]; 73 | dispatch_async(dispatch_get_main_queue(), ^{ 74 | _dynamicData = [[NSMutableArray alloc] initWithArray:data]; 75 | [self.tableView reloadData]; 76 | }); 77 | }); 78 | } 79 | 80 | #pragma mark - Table view data source 81 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 82 | // Return the number of rows in the section. 83 | return _dynamicData.count; 84 | } 85 | 86 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 87 | DynamicCell *cell = [DynamicCell cellWithTableView:tableView]; 88 | Dynamic *dynamic = [_dynamicData objectAtIndex:indexPath.row]; 89 | cell.dynamic = dynamic; 90 | 91 | return cell; 92 | } 93 | 94 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 95 | { 96 | Dynamic *dynamic = [_dynamicData objectAtIndex:indexPath.row]; 97 | return [DynamicCell heightOfCellWithModel:dynamic]; 98 | } 99 | 100 | 101 | /* 102 | // Override to support conditional editing of the table view. 103 | - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { 104 | // Return NO if you do not want the specified item to be editable. 105 | return YES; 106 | } 107 | */ 108 | 109 | /* 110 | // Override to support editing the table view. 111 | - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { 112 | if (editingStyle == UITableViewCellEditingStyleDelete) { 113 | // Delete the row from the data source 114 | [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; 115 | } else if (editingStyle == UITableViewCellEditingStyleInsert) { 116 | // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view 117 | } 118 | } 119 | */ 120 | 121 | /* 122 | // Override to support rearranging the table view. 123 | - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { 124 | } 125 | */ 126 | 127 | /* 128 | // Override to support conditional rearranging of the table view. 129 | - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { 130 | // Return NO if you do not want the item to be re-orderable. 131 | return YES; 132 | } 133 | */ 134 | 135 | /* 136 | #pragma mark - Navigation 137 | 138 | // In a storyboard-based application, you will often want to do a little preparation before navigation 139 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 140 | // Get the new view controller using [segue destinationViewController]. 141 | // Pass the selected object to the new view controller. 142 | } 143 | */ 144 | 145 | @end 146 | -------------------------------------------------------------------------------- /TextUtil/OpenSources/FMDB/FMDatabasePool.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMDatabasePool.h 3 | // fmdb 4 | // 5 | // Created by August Mueller on 6/22/11. 6 | // Copyright 2011 Flying Meat Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "sqlite3.h" 11 | 12 | @class FMDatabase; 13 | 14 | /** Pool of `` objects. 15 | 16 | ### See also 17 | 18 | - `` 19 | - `` 20 | 21 | @warning Before using `FMDatabasePool`, please consider using `` instead. 22 | 23 | If you really really really know what you're doing and `FMDatabasePool` is what 24 | you really really need (ie, you're using a read only database), OK you can use 25 | it. But just be careful not to deadlock! 26 | 27 | For an example on deadlocking, search for: 28 | `ONLY_USE_THE_POOL_IF_YOU_ARE_DOING_READS_OTHERWISE_YOULL_DEADLOCK_USE_FMDATABASEQUEUE_INSTEAD` 29 | in the main.m file. 30 | */ 31 | 32 | @interface FMDatabasePool : NSObject { 33 | NSString *_path; 34 | 35 | dispatch_queue_t _lockQueue; 36 | 37 | NSMutableArray *_databaseInPool; 38 | NSMutableArray *_databaseOutPool; 39 | 40 | __unsafe_unretained id _delegate; 41 | 42 | NSUInteger _maximumNumberOfDatabasesToCreate; 43 | int _openFlags; 44 | } 45 | 46 | /** Database path */ 47 | 48 | @property (atomic, retain) NSString *path; 49 | 50 | /** Delegate object */ 51 | 52 | @property (atomic, assign) id delegate; 53 | 54 | /** Maximum number of databases to create */ 55 | 56 | @property (atomic, assign) NSUInteger maximumNumberOfDatabasesToCreate; 57 | 58 | /** Open flags */ 59 | 60 | @property (atomic, readonly) int openFlags; 61 | 62 | 63 | ///--------------------- 64 | /// @name Initialization 65 | ///--------------------- 66 | 67 | /** Create pool using path. 68 | 69 | @param aPath The file path of the database. 70 | 71 | @return The `FMDatabasePool` object. `nil` on error. 72 | */ 73 | 74 | + (instancetype)databasePoolWithPath:(NSString*)aPath; 75 | 76 | /** Create pool using path and specified flags 77 | 78 | @param aPath The file path of the database. 79 | @param openFlags Flags passed to the openWithFlags method of the database 80 | 81 | @return The `FMDatabasePool` object. `nil` on error. 82 | */ 83 | 84 | + (instancetype)databasePoolWithPath:(NSString*)aPath flags:(int)openFlags; 85 | 86 | /** Create pool using path. 87 | 88 | @param aPath The file path of the database. 89 | 90 | @return The `FMDatabasePool` object. `nil` on error. 91 | */ 92 | 93 | - (instancetype)initWithPath:(NSString*)aPath; 94 | 95 | /** Create pool using path and specified flags. 96 | 97 | @param aPath The file path of the database. 98 | @param openFlags Flags passed to the openWithFlags method of the database 99 | 100 | @return The `FMDatabasePool` object. `nil` on error. 101 | */ 102 | 103 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags; 104 | 105 | ///------------------------------------------------ 106 | /// @name Keeping track of checked in/out databases 107 | ///------------------------------------------------ 108 | 109 | /** Number of checked-in databases in pool 110 | 111 | @returns Number of databases 112 | */ 113 | 114 | - (NSUInteger)countOfCheckedInDatabases; 115 | 116 | /** Number of checked-out databases in pool 117 | 118 | @returns Number of databases 119 | */ 120 | 121 | - (NSUInteger)countOfCheckedOutDatabases; 122 | 123 | /** Total number of databases in pool 124 | 125 | @returns Number of databases 126 | */ 127 | 128 | - (NSUInteger)countOfOpenDatabases; 129 | 130 | /** Release all databases in pool */ 131 | 132 | - (void)releaseAllDatabases; 133 | 134 | ///------------------------------------------ 135 | /// @name Perform database operations in pool 136 | ///------------------------------------------ 137 | 138 | /** Synchronously perform database operations in pool. 139 | 140 | @param block The code to be run on the `FMDatabasePool` pool. 141 | */ 142 | 143 | - (void)inDatabase:(void (^)(FMDatabase *db))block; 144 | 145 | /** Synchronously perform database operations in pool using transaction. 146 | 147 | @param block The code to be run on the `FMDatabasePool` pool. 148 | */ 149 | 150 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; 151 | 152 | /** Synchronously perform database operations in pool using deferred transaction. 153 | 154 | @param block The code to be run on the `FMDatabasePool` pool. 155 | */ 156 | 157 | - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; 158 | 159 | #if SQLITE_VERSION_NUMBER >= 3007000 160 | 161 | /** Synchronously perform database operations in pool using save point. 162 | 163 | @param block The code to be run on the `FMDatabasePool` pool. 164 | 165 | @return `NSError` object if error; `nil` if successful. 166 | 167 | @warning You can not nest these, since calling it will pull another database out of the pool and you'll get a deadlock. If you need to nest, use `<[FMDatabase startSavePointWithName:error:]>` instead. 168 | */ 169 | 170 | - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block; 171 | #endif 172 | 173 | @end 174 | 175 | 176 | /** FMDatabasePool delegate category 177 | 178 | This is a category that defines the protocol for the FMDatabasePool delegate 179 | */ 180 | 181 | @interface NSObject (FMDatabasePoolDelegate) 182 | 183 | /** Asks the delegate whether database should be added to the pool. 184 | 185 | @param pool The `FMDatabasePool` object. 186 | @param database The `FMDatabase` object. 187 | 188 | @return `YES` if it should add database to pool; `NO` if not. 189 | 190 | */ 191 | 192 | - (BOOL)databasePool:(FMDatabasePool*)pool shouldAddDatabaseToPool:(FMDatabase*)database; 193 | 194 | /** Tells the delegate that database was added to the pool. 195 | 196 | @param pool The `FMDatabasePool` object. 197 | @param database The `FMDatabase` object. 198 | 199 | */ 200 | 201 | - (void)databasePool:(FMDatabasePool*)pool didAddDatabase:(FMDatabase*)database; 202 | 203 | @end 204 | 205 | -------------------------------------------------------------------------------- /TextUtil/Chat/Views/YYFaceView.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYFaceView.m 3 | // 4 | // 5 | // Created by Joker on 14-1-6. 6 | // Copyright (c) 2014年 Mac. All rights reserved. 7 | // 8 | 9 | #import "YYFaceView.h" 10 | 11 | #define item_width 42 12 | #define item_height 45 13 | 14 | @implementation YYFaceView 15 | 16 | - (id)initWithFrame:(CGRect)frame 17 | { 18 | self = [super initWithFrame:frame]; 19 | if (self) { 20 | [self initData]; 21 | self.backgroundColor = [UIColor clearColor]; 22 | } 23 | return self; 24 | } 25 | 26 | /** 27 | * 行 row:3 28 | * 列 colum:7 29 | * 表情尺寸 30*30 pixels 30 | */ 31 | /* 32 | * 33 | items = [ 34 | ["表情1",“表情2”,“表情3”,......“表情28”], 35 | ["表情1",“表情2”,“表情3”,......“表情28”], 36 | ["表情1",“表情2”,“表情3”,......“表情28”] 37 | ]; 38 | 39 | */ 40 | 41 | - (void)initData 42 | { 43 | items = [[NSMutableArray alloc] init]; 44 | 45 | //---------------整理表情,整理成一个二维数组--------------- 46 | NSString *filePath = [[NSBundle mainBundle] pathForResource:@"emoticons" ofType:@"plist"]; 47 | NSArray *fileArray = [NSArray arrayWithContentsOfFile:filePath]; 48 | 49 | NSMutableArray *items2D = nil; 50 | for (int i=0; i 6) { 130 | colum = 6; 131 | } 132 | if (colum < 0) { 133 | colum = 0; 134 | } 135 | 136 | if (row > 2) { 137 | row = 1; 138 | } 139 | if (row < 0) { 140 | row = 0; 141 | } 142 | 143 | //计算选中表情的索引 144 | int index = colum + (row * 7); 145 | NSArray *item2D = [items objectAtIndex:page]; 146 | if (index >= item2D.count) { 147 | return; 148 | } 149 | NSDictionary *item = [item2D objectAtIndex:index]; 150 | NSString *faceName = [item objectForKey:@"cht"]; 151 | 152 | if (![self.selectedFaceName isEqualToString:faceName]) { 153 | //给放大镜添加上表情 154 | NSString *imageName = [item objectForKey:@"png"]; 155 | UIImage *image = [UIImage imageNamed:imageName]; 156 | 157 | UIImageView *faceItem = (UIImageView *)[magnifierView viewWithTag:2013]; 158 | faceItem.image = image; 159 | 160 | magnifierView.left = (page * 320) + colum *item_width; 161 | magnifierView.bottom = row *item_height + 30; 162 | 163 | self.selectedFaceName = faceName; 164 | } 165 | 166 | } 167 | 168 | #pragma mark - touch事件 169 | //touch 触摸开始 170 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 171 | { 172 | magnifierView.hidden = NO; 173 | UITouch *touch = [touches anyObject]; 174 | CGPoint point = [touch locationInView:self]; 175 | [self touchFace:point]; 176 | 177 | if ([self.superview isKindOfClass:[UIScrollView class]]) { 178 | UIScrollView *scrollView = (UIScrollView *)self.superview; 179 | scrollView.scrollEnabled = NO; 180 | } 181 | 182 | } 183 | 184 | //touch 触摸移动 185 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 186 | { 187 | UITouch *touch = [touches anyObject]; 188 | CGPoint point = [touch locationInView:self]; 189 | [self touchFace:point]; 190 | } 191 | 192 | //touch 触摸结束 193 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 194 | { 195 | magnifierView.hidden = YES; 196 | if ([self.superview isKindOfClass:[UIScrollView class]]) { 197 | UIScrollView *scrollView = (UIScrollView *)self.superview; 198 | scrollView.scrollEnabled = YES; 199 | } 200 | 201 | if (self.block != nil) { 202 | _block(_selectedFaceName); 203 | } 204 | } 205 | 206 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event 207 | { 208 | magnifierView.hidden = YES; 209 | if ([self.superview isKindOfClass:[UIScrollView class]]) { 210 | UIScrollView *scrollView = (UIScrollView *)self.superview; 211 | scrollView.scrollEnabled = YES; 212 | } 213 | } 214 | 215 | @end 216 | -------------------------------------------------------------------------------- /TextUtil/OpenSources/FMDB/FMDatabaseQueue.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMDatabaseQueue.h 3 | // fmdb 4 | // 5 | // Created by August Mueller on 6/22/11. 6 | // Copyright 2011 Flying Meat Inc. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "sqlite3.h" 11 | 12 | @class FMDatabase; 13 | 14 | /** To perform queries and updates on multiple threads, you'll want to use `FMDatabaseQueue`. 15 | 16 | Using a single instance of `` from multiple threads at once is a bad idea. It has always been OK to make a `` object *per thread*. Just don't share a single instance across threads, and definitely not across multiple threads at the same time. 17 | 18 | Instead, use `FMDatabaseQueue`. Here's how to use it: 19 | 20 | First, make your queue. 21 | 22 | FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath]; 23 | 24 | Then use it like so: 25 | 26 | [queue inDatabase:^(FMDatabase *db) { 27 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]]; 28 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]]; 29 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]]; 30 | 31 | FMResultSet *rs = [db executeQuery:@"select * from foo"]; 32 | while ([rs next]) { 33 | //… 34 | } 35 | }]; 36 | 37 | An easy way to wrap things up in a transaction can be done like this: 38 | 39 | [queue inTransaction:^(FMDatabase *db, BOOL *rollback) { 40 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]]; 41 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]]; 42 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]]; 43 | 44 | if (whoopsSomethingWrongHappened) { 45 | *rollback = YES; 46 | return; 47 | } 48 | // etc… 49 | [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:4]]; 50 | }]; 51 | 52 | `FMDatabaseQueue` will run the blocks on a serialized queue (hence the name of the class). So if you call `FMDatabaseQueue`'s methods from multiple threads at the same time, they will be executed in the order they are received. This way queries and updates won't step on each other's toes, and every one is happy. 53 | 54 | ### See also 55 | 56 | - `` 57 | 58 | @warning Do not instantiate a single `` object and use it across multiple threads. Use `FMDatabaseQueue` instead. 59 | 60 | @warning The calls to `FMDatabaseQueue`'s methods are blocking. So even though you are passing along blocks, they will **not** be run on another thread. 61 | 62 | */ 63 | 64 | @interface FMDatabaseQueue : NSObject { 65 | NSString *_path; 66 | dispatch_queue_t _queue; 67 | FMDatabase *_db; 68 | int _openFlags; 69 | } 70 | 71 | /** Path of database */ 72 | 73 | @property (atomic, retain) NSString *path; 74 | 75 | /** Open flags */ 76 | 77 | @property (atomic, readonly) int openFlags; 78 | 79 | ///---------------------------------------------------- 80 | /// @name Initialization, opening, and closing of queue 81 | ///---------------------------------------------------- 82 | 83 | /** Create queue using path. 84 | 85 | @param aPath The file path of the database. 86 | 87 | @return The `FMDatabaseQueue` object. `nil` on error. 88 | */ 89 | 90 | + (instancetype)databaseQueueWithPath:(NSString*)aPath; 91 | 92 | /** Create queue using path and specified flags. 93 | 94 | @param aPath The file path of the database. 95 | @param openFlags Flags passed to the openWithFlags method of the database 96 | 97 | @return The `FMDatabaseQueue` object. `nil` on error. 98 | */ 99 | + (instancetype)databaseQueueWithPath:(NSString*)aPath flags:(int)openFlags; 100 | 101 | /** Create queue using path. 102 | 103 | @param aPath The file path of the database. 104 | 105 | @return The `FMDatabaseQueue` object. `nil` on error. 106 | */ 107 | 108 | - (instancetype)initWithPath:(NSString*)aPath; 109 | 110 | /** Create queue using path and specified flags. 111 | 112 | @param aPath The file path of the database. 113 | @param openFlags Flags passed to the openWithFlags method of the database 114 | 115 | @return The `FMDatabaseQueue` object. `nil` on error. 116 | */ 117 | 118 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags; 119 | 120 | /** Returns the Class of 'FMDatabase' subclass, that will be used to instantiate database object. 121 | 122 | Subclasses can override this method to return specified Class of 'FMDatabase' subclass. 123 | 124 | @return The Class of 'FMDatabase' subclass, that will be used to instantiate database object. 125 | */ 126 | 127 | + (Class)databaseClass; 128 | 129 | /** Close database used by queue. */ 130 | 131 | - (void)close; 132 | 133 | ///----------------------------------------------- 134 | /// @name Dispatching database operations to queue 135 | ///----------------------------------------------- 136 | 137 | /** Synchronously perform database operations on queue. 138 | 139 | @param block The code to be run on the queue of `FMDatabaseQueue` 140 | */ 141 | 142 | - (void)inDatabase:(void (^)(FMDatabase *db))block; 143 | 144 | /** Synchronously perform database operations on queue, using transactions. 145 | 146 | @param block The code to be run on the queue of `FMDatabaseQueue` 147 | */ 148 | 149 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; 150 | 151 | /** Synchronously perform database operations on queue, using deferred transactions. 152 | 153 | @param block The code to be run on the queue of `FMDatabaseQueue` 154 | */ 155 | 156 | - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block; 157 | 158 | ///----------------------------------------------- 159 | /// @name Dispatching database operations to queue 160 | ///----------------------------------------------- 161 | 162 | /** Synchronously perform database operations using save point. 163 | 164 | @param block The code to be run on the queue of `FMDatabaseQueue` 165 | */ 166 | 167 | #if SQLITE_VERSION_NUMBER >= 3007000 168 | // NOTE: you can not nest these, since calling it will pull another database out of the pool and you'll get a deadlock. 169 | // If you need to nest, use FMDatabase's startSavePointWithName:error: instead. 170 | - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block; 171 | #endif 172 | 173 | @end 174 | 175 | -------------------------------------------------------------------------------- /TextUtil/Chat/Views/ChatCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // ChatCell.m 3 | // TextUtil 4 | // 5 | // Created by zx_04 on 15/8/19. 6 | // Copyright (c) 2015年 joker. All rights reserved. 7 | // 8 | 9 | #import "ChatCell.h" 10 | #import "ChatMessage.h" 11 | #import "Utility.h" 12 | #import "UIImage+Extension.h" 13 | 14 | #define kContentFontSize 16.0f //内容字体大小 15 | #define kPadding 5.0f //控件间隙 16 | #define kEdgeInsetsWidth 20.0f //内容内边距宽度 17 | 18 | @interface ChatCell () 19 | 20 | /** 头像视图 */ 21 | @property (nonatomic, retain) UIImageView *faceImageView; 22 | /** 背景图 */ 23 | @property (nonatomic, retain) UIButton *bgButton; 24 | /** 文字内容视图 */ 25 | @property (nonatomic, retain) UILabel *contentLabel; 26 | 27 | @end 28 | 29 | @implementation ChatCell 30 | 31 | #pragma mark - life cirle method 32 | - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier 33 | { 34 | self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; 35 | if (self) { 36 | [self initSubViews]; 37 | } 38 | return self; 39 | } 40 | 41 | - (void)initSubViews 42 | { 43 | // 初始化头像视图 44 | _faceImageView = [[UIImageView alloc] initWithFrame:CGRectZero]; 45 | _faceImageView.layer.cornerRadius = 5; 46 | _faceImageView.layer.masksToBounds = YES; 47 | _faceImageView.backgroundColor = [UIColor clearColor]; 48 | [self.contentView addSubview:_faceImageView]; 49 | 50 | //初始化正文视图 51 | _bgButton = [[UIButton alloc] initWithFrame:CGRectZero]; 52 | [self.contentView addSubview:_bgButton]; 53 | 54 | //初始化正文视图 55 | _contentLabel = [[UILabel alloc] initWithFrame:CGRectZero]; 56 | _contentLabel.font = [UIFont systemFontOfSize:kContentFontSize]; 57 | _contentLabel.numberOfLines = 0; 58 | [_bgButton addSubview:_contentLabel]; 59 | } 60 | 61 | #pragma mark - set subViews frame 62 | /** 设置头像的frame和内容 */ 63 | - (void)setFaceFrame 64 | { 65 | CGFloat width = 40; 66 | CGFloat height = 40; 67 | if (_message.isSender) {//如果是自己发送 68 | _faceImageView.frame = CGRectMake(kWidth-width-kPadding, 10, width, height); 69 | } else { 70 | _faceImageView.frame = CGRectMake(kPadding, 10, width, height); 71 | } 72 | if (_message.isSender) { 73 | _faceImageView.image = [UIImage imageNamed:@"header_QQ"]; 74 | } else { 75 | _faceImageView.image = [UIImage imageNamed:@"header_wechat"]; 76 | } 77 | } 78 | 79 | /** 设置文字类型message的cellframe */ 80 | - (void)setMessageFrame 81 | { 82 | // 1、计算文字的宽高 83 | float textMaxWidth = kWidth-40-kPadding *2-60; //60是消息框体距离右侧或者左侧的距离 84 | 85 | // NSMutableAttributedString *attrStr = [Utility emotionStrWithString:_message.content]; 86 | NSMutableAttributedString *attrStr = [Utility emotionStrWithString:_message.content plistName:@"emoticons.plist" y:-8]; 87 | [attrStr addAttribute:NSFontAttributeName 88 | value:[UIFont systemFontOfSize:kContentFontSize] 89 | range:NSMakeRange(0, attrStr.length)]; 90 | CGSize textSize = [attrStr boundingRectWithSize:CGSizeMake(textMaxWidth, CGFLOAT_MAX) 91 | options:NSStringDrawingUsesLineFragmentOrigin 92 | context:nil].size; 93 | 94 | _contentLabel.attributedText = attrStr; 95 | 96 | _contentLabel.frame = CGRectMake(kEdgeInsetsWidth, kEdgeInsetsWidth, textSize.width, textSize.height); 97 | // 2、计算背景图片的frame,X坐标发送和接收计算方式不一样 98 | CGFloat bgY = CGRectGetMinY(_faceImageView.frame); 99 | CGFloat width = textSize.width + kEdgeInsetsWidth*2; 100 | CGFloat height = textSize.height + kEdgeInsetsWidth*2; 101 | UIImage *bgImage; //声明一个背景图片对象 102 | UIImage *bgHighImage; 103 | // 3、判断是否为自己发送,来设置frame以及背景图片 104 | if (_message.isSender) { //如果是自己发送的 105 | CGFloat bgX = kWidth-kPadding*2-CGRectGetWidth(_faceImageView.frame)-width; 106 | _bgButton.frame = CGRectMake(bgX,bgY, width, height); 107 | [_bgButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; 108 | bgImage = [UIImage resizableImageWithName:@"chat_send_nor"]; 109 | bgHighImage = [UIImage resizableImageWithName:@"chat_send_press_pic"]; 110 | } else { 111 | CGFloat bgX = CGRectGetMaxX(_faceImageView.frame)+5; 112 | _bgButton.frame = CGRectMake(bgX, bgY, width, height); 113 | [_bgButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 114 | bgImage = [UIImage resizableImageWithName:@"chat_recive_nor"]; 115 | bgHighImage = [UIImage resizableImageWithName:@"chat_recive_press_pic"]; 116 | } 117 | [_bgButton setBackgroundImage:bgImage forState:UIControlStateNormal]; 118 | [_bgButton setBackgroundImage:bgHighImage forState:UIControlStateHighlighted]; 119 | } 120 | 121 | 122 | #pragma mark - class method 123 | + (instancetype)cellWithTableView:(UITableView *)tableView 124 | { 125 | static NSString *identifier = @"chatCell"; 126 | ChatCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; 127 | if (cell == nil) { 128 | cell = [[ChatCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]; 129 | cell.backgroundColor = [UIColor clearColor]; 130 | cell.contentView.backgroundColor = [UIColor clearColor]; 131 | } 132 | return cell; 133 | } 134 | 135 | /** 计算cell 的高度 */ 136 | + (CGFloat)heightOfCellWithMessage:(ChatMessage *)message 137 | { 138 | CGFloat height = 0; 139 | 140 | float textMaxWidth = kWidth-40-kPadding *2-60; //60是消息框体距离右侧或者左侧的距离 141 | 142 | // NSMutableAttributedString *attrStr = [Utility emotionStrWithString:message.content]; 143 | NSMutableAttributedString *attrStr = [Utility emotionStrWithString:message.content plistName:@"emoticons.plist" y:-8]; 144 | [attrStr addAttribute:NSFontAttributeName 145 | value:[UIFont systemFontOfSize:kContentFontSize] 146 | range:NSMakeRange(0, attrStr.length)]; 147 | CGSize textSize = [attrStr boundingRectWithSize:CGSizeMake(textMaxWidth, CGFLOAT_MAX) 148 | options:NSStringDrawingUsesLineFragmentOrigin 149 | context:nil].size; 150 | height += (textSize.height+kEdgeInsetsWidth*2); 151 | 152 | if (height < 60) { 153 | height = 60; 154 | } 155 | return height; 156 | } 157 | 158 | #pragma mark - setter and getter 159 | - (void)setMessage:(ChatMessage *)message 160 | { 161 | if (_message != message) { 162 | _message = message; 163 | } 164 | 165 | //设置头像 166 | [self setFaceFrame]; 167 | 168 | //设置内容 169 | [self setMessageFrame]; 170 | } 171 | 172 | @end 173 | -------------------------------------------------------------------------------- /TextUtil/Chat/Controllers/ChatViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ChatViewController.m 3 | // TextUtil 4 | // 5 | // Created by zx_04 on 15/8/19. 6 | // Copyright (c) 2015年 joker. All rights reserved. 7 | // 8 | 9 | #import "ChatViewController.h" 10 | 11 | #import "ChatCell.h" 12 | #import "ChatMessage.h" 13 | #import "YYFaceScrollView.h" 14 | 15 | @interface ChatViewController () 16 | 17 | @property (weak, nonatomic) IBOutlet UITableView *tableView; 18 | @property (weak, nonatomic) IBOutlet UIView *bottomView; 19 | @property (weak, nonatomic) IBOutlet UITextField *textField; 20 | /** 表情视图 */ 21 | @property (nonatomic, strong) YYFaceScrollView *faceView; 22 | 23 | @property (nonatomic, strong) NSMutableArray *messages; 24 | 25 | @end 26 | 27 | @implementation ChatViewController 28 | 29 | - (void)viewDidLoad { 30 | [super viewDidLoad]; 31 | // Do any additional setup after loading the view. 32 | 33 | self.view.backgroundColor = VIEW_BGCOLOR; 34 | 35 | _tableView.tableFooterView = [UIView new]; 36 | _tableView.showsVerticalScrollIndicator = NO; 37 | _tableView.backgroundColor = [UIColor clearColor]; 38 | 39 | UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(cancelFocus)]; 40 | [self.tableView addGestureRecognizer:tapGesture]; 41 | 42 | //加载历史聊天记录 43 | [self loadChatRecords]; 44 | 45 | } 46 | 47 | - (void)viewWillAppear:(BOOL)animated 48 | { 49 | [super viewWillAppear:animated]; 50 | 51 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; 52 | } 53 | 54 | - (void)viewWillDisappear:(BOOL)animated 55 | { 56 | [super viewWillDisappear:animated]; 57 | 58 | [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; 59 | } 60 | 61 | - (void)loadChatRecords 62 | { 63 | dispatch_async(dispatch_get_global_queue(0, 0), ^{ 64 | NSArray *data = [ChatMessage findAll]; 65 | dispatch_async(dispatch_get_main_queue(), ^{ 66 | _messages = [[NSMutableArray alloc] initWithArray:data]; 67 | [_tableView reloadData]; 68 | }); 69 | }); 70 | } 71 | 72 | /** 取消事件的焦点 */ 73 | - (void)cancelFocus 74 | { 75 | self.textField.text = nil; 76 | [self.textField resignFirstResponder]; 77 | 78 | [UIView animateWithDuration:0.3f animations:^{ 79 | // 1、修改输入框视图的位置 80 | _bottomView.bottom = kHeight-64; 81 | // 修改表情视图的位置 82 | _faceView.top = kHeight-64; 83 | // 2、修改表格的高度 84 | _tableView.height = _bottomView.top; 85 | }]; 86 | } 87 | 88 | - (void)sendMessage:(NSString *)text 89 | { 90 | text = [text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 91 | if (text.length == 0) { 92 | return; 93 | } 94 | ChatMessage *chatMessage = [[ChatMessage alloc] init]; 95 | chatMessage.isSender = YES; 96 | chatMessage.content = text; 97 | [chatMessage save]; 98 | self.textField.text = nil; 99 | [_messages addObject:chatMessage]; 100 | [_tableView reloadData]; 101 | 102 | [self tableViewScrollToBottom]; 103 | } 104 | 105 | - (void)tableViewScrollToBottom 106 | { 107 | if (_messages.count > 0) { 108 | NSIndexPath *indexPath = [NSIndexPath indexPathForRow:(_messages.count-1) inSection:0]; 109 | [_tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES]; 110 | } 111 | } 112 | 113 | - (IBAction)emtionClick:(id)sender { 114 | NSLog(@"%s--emtionClick",__func__); 115 | [self.textField resignFirstResponder]; 116 | if (_faceView == nil) { 117 | __block __weak ChatViewController *this = self; 118 | 119 | _faceView = [[YYFaceScrollView alloc] initWithSelectBlock:^(NSString *faceName) { 120 | NSString *text = this.textField.text; 121 | NSString *appendText = [text stringByAppendingString:faceName]; 122 | this.textField.text = appendText; 123 | }]; 124 | _faceView.backgroundColor = RGBColor(220, 220, 220, 1); 125 | _faceView.top = kHeight - 20 - 44; 126 | _faceView.clipsToBounds = NO; 127 | _faceView.sendBlock = ^{ 128 | NSString* fullText = this.textField.text; 129 | [this sendMessage:fullText]; 130 | [this cancelFocus]; 131 | }; 132 | [self.view addSubview:_faceView]; 133 | } 134 | float height = _faceView.height; 135 | //设置键盘动画 136 | __block CGRect frame; 137 | [UIView animateWithDuration:0.3 animations:^{ 138 | _faceView.top = kHeight - 20 - 44 - height; 139 | //调整bottomView的高度 140 | self.bottomView.bottom = _faceView.top; 141 | frame = _bottomView.frame; 142 | self.inputView.frame = frame; 143 | }]; 144 | } 145 | 146 | #pragma mark - UITextFieldDelegate 147 | - (BOOL)textFieldShouldReturn:(UITextField *)textField 148 | { 149 | [self sendMessage:_textField.text]; 150 | return YES; 151 | } 152 | 153 | #pragma mark - Notification event 154 | - (void)keyboardWillShow:(NSNotification *)notification 155 | { 156 | NSDictionary *userInfo = [notification userInfo]; 157 | NSValue *value = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey]; 158 | CGRect frame = value.CGRectValue; 159 | 160 | NSNumber *duration = [userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey]; 161 | NSNumber *curve = [userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey]; 162 | 163 | // 添加移动动画,使视图跟随键盘移动 164 | [UIView animateWithDuration:duration.doubleValue animations:^{ 165 | [UIView setAnimationBeginsFromCurrentState:YES]; 166 | [UIView setAnimationCurve:[curve intValue]]; 167 | CGFloat bottom = kHeight-frame.size.height-64; 168 | //1.修改输入框View的位置 169 | _bottomView.bottom = bottom; 170 | //2.修改tableView的高度 171 | _tableView.height = _bottomView.top; 172 | } completion:^(BOOL finished) { 173 | [self tableViewScrollToBottom]; 174 | }]; 175 | } 176 | 177 | #pragma mark - UITableViewDataSource 178 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 179 | { 180 | return _messages.count; 181 | } 182 | 183 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 184 | { 185 | ChatCell *cell = [ChatCell cellWithTableView:tableView]; 186 | cell.message = [_messages objectAtIndex:indexPath.row]; 187 | 188 | return cell; 189 | } 190 | 191 | -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 192 | { 193 | ChatMessage *message = [_messages objectAtIndex:indexPath.row]; 194 | 195 | return [ChatCell heightOfCellWithMessage:message]; 196 | } 197 | 198 | @end 199 | -------------------------------------------------------------------------------- /TextUtil/OpenSources/FMDB/FMDatabaseQueue.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMDatabaseQueue.m 3 | // fmdb 4 | // 5 | // Created by August Mueller on 6/22/11. 6 | // Copyright 2011 Flying Meat Inc. All rights reserved. 7 | // 8 | 9 | #import "FMDatabaseQueue.h" 10 | #import "FMDatabase.h" 11 | 12 | /* 13 | 14 | Note: we call [self retain]; before using dispatch_sync, just incase 15 | FMDatabaseQueue is released on another thread and we're in the middle of doing 16 | something in dispatch_sync 17 | 18 | */ 19 | 20 | /* 21 | * A key used to associate the FMDatabaseQueue object with the dispatch_queue_t it uses. 22 | * This in turn is used for deadlock detection by seeing if inDatabase: is called on 23 | * the queue's dispatch queue, which should not happen and causes a deadlock. 24 | */ 25 | static const void * const kDispatchQueueSpecificKey = &kDispatchQueueSpecificKey; 26 | 27 | @implementation FMDatabaseQueue 28 | 29 | @synthesize path = _path; 30 | @synthesize openFlags = _openFlags; 31 | 32 | + (instancetype)databaseQueueWithPath:(NSString*)aPath { 33 | 34 | FMDatabaseQueue *q = [[self alloc] initWithPath:aPath]; 35 | 36 | FMDBAutorelease(q); 37 | 38 | return q; 39 | } 40 | 41 | + (instancetype)databaseQueueWithPath:(NSString*)aPath flags:(int)openFlags { 42 | 43 | FMDatabaseQueue *q = [[self alloc] initWithPath:aPath flags:openFlags]; 44 | 45 | FMDBAutorelease(q); 46 | 47 | return q; 48 | } 49 | 50 | + (Class)databaseClass { 51 | return [FMDatabase class]; 52 | } 53 | 54 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags { 55 | 56 | self = [super init]; 57 | 58 | if (self != nil) { 59 | 60 | _db = [[[self class] databaseClass] databaseWithPath:aPath]; 61 | FMDBRetain(_db); 62 | 63 | #if SQLITE_VERSION_NUMBER >= 3005000 64 | BOOL success = [_db openWithFlags:openFlags]; 65 | #else 66 | BOOL success = [_db open]; 67 | #endif 68 | if (!success) { 69 | NSLog(@"Could not create database queue for path %@", aPath); 70 | FMDBRelease(self); 71 | return 0x00; 72 | } 73 | 74 | _path = FMDBReturnRetained(aPath); 75 | 76 | _queue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL); 77 | dispatch_queue_set_specific(_queue, kDispatchQueueSpecificKey, (__bridge void *)self, NULL); 78 | _openFlags = openFlags; 79 | } 80 | 81 | return self; 82 | } 83 | 84 | - (instancetype)initWithPath:(NSString*)aPath { 85 | 86 | // default flags for sqlite3_open 87 | return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE]; 88 | } 89 | 90 | - (instancetype)init { 91 | return [self initWithPath:nil]; 92 | } 93 | 94 | 95 | - (void)dealloc { 96 | 97 | FMDBRelease(_db); 98 | FMDBRelease(_path); 99 | 100 | if (_queue) { 101 | FMDBDispatchQueueRelease(_queue); 102 | _queue = 0x00; 103 | } 104 | #if ! __has_feature(objc_arc) 105 | [super dealloc]; 106 | #endif 107 | } 108 | 109 | - (void)close { 110 | FMDBRetain(self); 111 | dispatch_sync(_queue, ^() { 112 | [self->_db close]; 113 | FMDBRelease(_db); 114 | self->_db = 0x00; 115 | }); 116 | FMDBRelease(self); 117 | } 118 | 119 | - (FMDatabase*)database { 120 | if (!_db) { 121 | _db = FMDBReturnRetained([FMDatabase databaseWithPath:_path]); 122 | 123 | #if SQLITE_VERSION_NUMBER >= 3005000 124 | BOOL success = [_db openWithFlags:_openFlags]; 125 | #else 126 | BOOL success = [_db open]; 127 | #endif 128 | if (!success) { 129 | NSLog(@"FMDatabaseQueue could not reopen database for path %@", _path); 130 | FMDBRelease(_db); 131 | _db = 0x00; 132 | return 0x00; 133 | } 134 | } 135 | 136 | return _db; 137 | } 138 | 139 | - (void)inDatabase:(void (^)(FMDatabase *db))block { 140 | /* Get the currently executing queue (which should probably be nil, but in theory could be another DB queue 141 | * and then check it against self to make sure we're not about to deadlock. */ 142 | FMDatabaseQueue *currentSyncQueue = (__bridge id)dispatch_get_specific(kDispatchQueueSpecificKey); 143 | assert(currentSyncQueue != self && "inDatabase: was called reentrantly on the same queue, which would lead to a deadlock"); 144 | 145 | FMDBRetain(self); 146 | 147 | dispatch_sync(_queue, ^() { 148 | 149 | FMDatabase *db = [self database]; 150 | block(db); 151 | 152 | if ([db hasOpenResultSets]) { 153 | NSLog(@"Warning: there is at least one open result set around after performing [FMDatabaseQueue inDatabase:]"); 154 | 155 | #if defined(DEBUG) && DEBUG 156 | NSSet *openSetCopy = FMDBReturnAutoreleased([[db valueForKey:@"_openResultSets"] copy]); 157 | for (NSValue *rsInWrappedInATastyValueMeal in openSetCopy) { 158 | FMResultSet *rs = (FMResultSet *)[rsInWrappedInATastyValueMeal pointerValue]; 159 | NSLog(@"query: '%@'", [rs query]); 160 | } 161 | #endif 162 | } 163 | }); 164 | 165 | FMDBRelease(self); 166 | } 167 | 168 | 169 | - (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(FMDatabase *db, BOOL *rollback))block { 170 | FMDBRetain(self); 171 | dispatch_sync(_queue, ^() { 172 | 173 | BOOL shouldRollback = NO; 174 | 175 | if (useDeferred) { 176 | [[self database] beginDeferredTransaction]; 177 | } 178 | else { 179 | [[self database] beginTransaction]; 180 | } 181 | 182 | block([self database], &shouldRollback); 183 | 184 | if (shouldRollback) { 185 | [[self database] rollback]; 186 | } 187 | else { 188 | [[self database] commit]; 189 | } 190 | }); 191 | 192 | FMDBRelease(self); 193 | } 194 | 195 | - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { 196 | [self beginTransaction:YES withBlock:block]; 197 | } 198 | 199 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { 200 | [self beginTransaction:NO withBlock:block]; 201 | } 202 | 203 | #if SQLITE_VERSION_NUMBER >= 3007000 204 | - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block { 205 | 206 | static unsigned long savePointIdx = 0; 207 | __block NSError *err = 0x00; 208 | FMDBRetain(self); 209 | dispatch_sync(_queue, ^() { 210 | 211 | NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++]; 212 | 213 | BOOL shouldRollback = NO; 214 | 215 | if ([[self database] startSavePointWithName:name error:&err]) { 216 | 217 | block([self database], &shouldRollback); 218 | 219 | if (shouldRollback) { 220 | // We need to rollback and release this savepoint to remove it 221 | [[self database] rollbackToSavePointWithName:name error:&err]; 222 | } 223 | [[self database] releaseSavePointWithName:name error:&err]; 224 | 225 | } 226 | }); 227 | FMDBRelease(self); 228 | return err; 229 | } 230 | #endif 231 | 232 | @end 233 | -------------------------------------------------------------------------------- /TextUtil/OpenSources/FMDB/FMDatabaseAdditions.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMDatabaseAdditions.m 3 | // fmdb 4 | // 5 | // Created by August Mueller on 10/30/05. 6 | // Copyright 2005 Flying Meat Inc.. All rights reserved. 7 | // 8 | 9 | #import "FMDatabase.h" 10 | #import "FMDatabaseAdditions.h" 11 | #import "TargetConditionals.h" 12 | 13 | @interface FMDatabase (PrivateStuff) 14 | - (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args; 15 | @end 16 | 17 | @implementation FMDatabase (FMDatabaseAdditions) 18 | 19 | #define RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(type, sel) \ 20 | va_list args; \ 21 | va_start(args, query); \ 22 | FMResultSet *resultSet = [self executeQuery:query withArgumentsInArray:0x00 orDictionary:0x00 orVAList:args]; \ 23 | va_end(args); \ 24 | if (![resultSet next]) { return (type)0; } \ 25 | type ret = [resultSet sel:0]; \ 26 | [resultSet close]; \ 27 | [resultSet setParentDB:nil]; \ 28 | return ret; 29 | 30 | 31 | - (NSString*)stringForQuery:(NSString*)query, ... { 32 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSString *, stringForColumnIndex); 33 | } 34 | 35 | - (int)intForQuery:(NSString*)query, ... { 36 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(int, intForColumnIndex); 37 | } 38 | 39 | - (long)longForQuery:(NSString*)query, ... { 40 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(long, longForColumnIndex); 41 | } 42 | 43 | - (BOOL)boolForQuery:(NSString*)query, ... { 44 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(BOOL, boolForColumnIndex); 45 | } 46 | 47 | - (double)doubleForQuery:(NSString*)query, ... { 48 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(double, doubleForColumnIndex); 49 | } 50 | 51 | - (NSData*)dataForQuery:(NSString*)query, ... { 52 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSData *, dataForColumnIndex); 53 | } 54 | 55 | - (NSDate*)dateForQuery:(NSString*)query, ... { 56 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSDate *, dateForColumnIndex); 57 | } 58 | 59 | 60 | - (BOOL)tableExists:(NSString*)tableName { 61 | 62 | tableName = [tableName lowercaseString]; 63 | 64 | FMResultSet *rs = [self executeQuery:@"select [sql] from sqlite_master where [type] = 'table' and lower(name) = ?", tableName]; 65 | 66 | //if at least one next exists, table exists 67 | BOOL returnBool = [rs next]; 68 | 69 | //close and free object 70 | [rs close]; 71 | 72 | return returnBool; 73 | } 74 | 75 | /* 76 | get table with list of tables: result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING] 77 | check if table exist in database (patch from OZLB) 78 | */ 79 | - (FMResultSet*)getSchema { 80 | 81 | //result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING] 82 | FMResultSet *rs = [self executeQuery:@"SELECT type, name, tbl_name, rootpage, sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type != 'meta' AND name NOT LIKE 'sqlite_%' ORDER BY tbl_name, type DESC, name"]; 83 | 84 | return rs; 85 | } 86 | 87 | /* 88 | get table schema: result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER] 89 | */ 90 | - (FMResultSet*)getTableSchema:(NSString*)tableName { 91 | 92 | //result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER] 93 | FMResultSet *rs = [self executeQuery:[NSString stringWithFormat: @"pragma table_info('%@')", tableName]]; 94 | 95 | return rs; 96 | } 97 | 98 | - (BOOL)columnExists:(NSString*)columnName inTableWithName:(NSString*)tableName { 99 | 100 | BOOL returnBool = NO; 101 | 102 | tableName = [tableName lowercaseString]; 103 | columnName = [columnName lowercaseString]; 104 | 105 | FMResultSet *rs = [self getTableSchema:tableName]; 106 | 107 | //check if column is present in table schema 108 | while ([rs next]) { 109 | if ([[[rs stringForColumn:@"name"] lowercaseString] isEqualToString:columnName]) { 110 | returnBool = YES; 111 | break; 112 | } 113 | } 114 | 115 | //If this is not done FMDatabase instance stays out of pool 116 | [rs close]; 117 | 118 | return returnBool; 119 | } 120 | 121 | 122 | #if SQLITE_VERSION_NUMBER >= 3007017 123 | 124 | - (uint32_t)applicationID { 125 | 126 | uint32_t r = 0; 127 | 128 | FMResultSet *rs = [self executeQuery:@"pragma application_id"]; 129 | 130 | if ([rs next]) { 131 | r = (uint32_t)[rs longLongIntForColumnIndex:0]; 132 | } 133 | 134 | [rs close]; 135 | 136 | return r; 137 | } 138 | 139 | - (void)setApplicationID:(uint32_t)appID { 140 | NSString *query = [NSString stringWithFormat:@"pragma application_id=%d", appID]; 141 | FMResultSet *rs = [self executeQuery:query]; 142 | [rs next]; 143 | [rs close]; 144 | } 145 | 146 | 147 | #if TARGET_OS_MAC && !TARGET_OS_IPHONE 148 | - (NSString*)applicationIDString { 149 | NSString *s = NSFileTypeForHFSTypeCode([self applicationID]); 150 | 151 | assert([s length] == 6); 152 | 153 | s = [s substringWithRange:NSMakeRange(1, 4)]; 154 | 155 | 156 | return s; 157 | 158 | } 159 | 160 | - (void)setApplicationIDString:(NSString*)s { 161 | 162 | if ([s length] != 4) { 163 | NSLog(@"setApplicationIDString: string passed is not exactly 4 chars long. (was %ld)", [s length]); 164 | } 165 | 166 | [self setApplicationID:NSHFSTypeCodeFromFileType([NSString stringWithFormat:@"'%@'", s])]; 167 | } 168 | 169 | 170 | #endif 171 | 172 | #endif 173 | 174 | - (uint32_t)userVersion { 175 | uint32_t r = 0; 176 | 177 | FMResultSet *rs = [self executeQuery:@"pragma user_version"]; 178 | 179 | if ([rs next]) { 180 | r = (uint32_t)[rs longLongIntForColumnIndex:0]; 181 | } 182 | 183 | [rs close]; 184 | return r; 185 | } 186 | 187 | - (void)setUserVersion:(uint32_t)version { 188 | NSString *query = [NSString stringWithFormat:@"pragma user_version = %d", version]; 189 | FMResultSet *rs = [self executeQuery:query]; 190 | [rs next]; 191 | [rs close]; 192 | } 193 | 194 | #pragma clang diagnostic push 195 | #pragma clang diagnostic ignored "-Wdeprecated-implementations" 196 | 197 | - (BOOL)columnExists:(NSString*)tableName columnName:(NSString*)columnName __attribute__ ((deprecated)) { 198 | return [self columnExists:columnName inTableWithName:tableName]; 199 | } 200 | 201 | #pragma clang diagnostic pop 202 | 203 | 204 | - (BOOL)validateSQL:(NSString*)sql error:(NSError**)error { 205 | sqlite3_stmt *pStmt = NULL; 206 | BOOL validationSucceeded = YES; 207 | 208 | int rc = sqlite3_prepare_v2(_db, [sql UTF8String], -1, &pStmt, 0); 209 | if (rc != SQLITE_OK) { 210 | validationSucceeded = NO; 211 | if (error) { 212 | *error = [NSError errorWithDomain:NSCocoaErrorDomain 213 | code:[self lastErrorCode] 214 | userInfo:[NSDictionary dictionaryWithObject:[self lastErrorMessage] 215 | forKey:NSLocalizedDescriptionKey]]; 216 | } 217 | } 218 | 219 | sqlite3_finalize(pStmt); 220 | 221 | return validationSucceeded; 222 | } 223 | 224 | @end 225 | -------------------------------------------------------------------------------- /TextUtil/OpenSources/FMDB/FMDatabasePool.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMDatabasePool.m 3 | // fmdb 4 | // 5 | // Created by August Mueller on 6/22/11. 6 | // Copyright 2011 Flying Meat Inc. All rights reserved. 7 | // 8 | 9 | #import "FMDatabasePool.h" 10 | #import "FMDatabase.h" 11 | 12 | @interface FMDatabasePool() 13 | 14 | - (void)pushDatabaseBackInPool:(FMDatabase*)db; 15 | - (FMDatabase*)db; 16 | 17 | @end 18 | 19 | 20 | @implementation FMDatabasePool 21 | @synthesize path=_path; 22 | @synthesize delegate=_delegate; 23 | @synthesize maximumNumberOfDatabasesToCreate=_maximumNumberOfDatabasesToCreate; 24 | @synthesize openFlags=_openFlags; 25 | 26 | 27 | + (instancetype)databasePoolWithPath:(NSString*)aPath { 28 | return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath]); 29 | } 30 | 31 | + (instancetype)databasePoolWithPath:(NSString*)aPath flags:(int)openFlags { 32 | return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath flags:openFlags]); 33 | } 34 | 35 | - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags { 36 | 37 | self = [super init]; 38 | 39 | if (self != nil) { 40 | _path = [aPath copy]; 41 | _lockQueue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL); 42 | _databaseInPool = FMDBReturnRetained([NSMutableArray array]); 43 | _databaseOutPool = FMDBReturnRetained([NSMutableArray array]); 44 | _openFlags = openFlags; 45 | } 46 | 47 | return self; 48 | } 49 | 50 | - (instancetype)initWithPath:(NSString*)aPath 51 | { 52 | // default flags for sqlite3_open 53 | return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE]; 54 | } 55 | 56 | - (instancetype)init { 57 | return [self initWithPath:nil]; 58 | } 59 | 60 | 61 | - (void)dealloc { 62 | 63 | _delegate = 0x00; 64 | FMDBRelease(_path); 65 | FMDBRelease(_databaseInPool); 66 | FMDBRelease(_databaseOutPool); 67 | 68 | if (_lockQueue) { 69 | FMDBDispatchQueueRelease(_lockQueue); 70 | _lockQueue = 0x00; 71 | } 72 | #if ! __has_feature(objc_arc) 73 | [super dealloc]; 74 | #endif 75 | } 76 | 77 | 78 | - (void)executeLocked:(void (^)(void))aBlock { 79 | dispatch_sync(_lockQueue, aBlock); 80 | } 81 | 82 | - (void)pushDatabaseBackInPool:(FMDatabase*)db { 83 | 84 | if (!db) { // db can be null if we set an upper bound on the # of databases to create. 85 | return; 86 | } 87 | 88 | [self executeLocked:^() { 89 | 90 | if ([self->_databaseInPool containsObject:db]) { 91 | [[NSException exceptionWithName:@"Database already in pool" reason:@"The FMDatabase being put back into the pool is already present in the pool" userInfo:nil] raise]; 92 | } 93 | 94 | [self->_databaseInPool addObject:db]; 95 | [self->_databaseOutPool removeObject:db]; 96 | 97 | }]; 98 | } 99 | 100 | - (FMDatabase*)db { 101 | 102 | __block FMDatabase *db; 103 | 104 | 105 | [self executeLocked:^() { 106 | db = [self->_databaseInPool lastObject]; 107 | 108 | BOOL shouldNotifyDelegate = NO; 109 | 110 | if (db) { 111 | [self->_databaseOutPool addObject:db]; 112 | [self->_databaseInPool removeLastObject]; 113 | } 114 | else { 115 | 116 | if (self->_maximumNumberOfDatabasesToCreate) { 117 | NSUInteger currentCount = [self->_databaseOutPool count] + [self->_databaseInPool count]; 118 | 119 | if (currentCount >= self->_maximumNumberOfDatabasesToCreate) { 120 | NSLog(@"Maximum number of databases (%ld) has already been reached!", (long)currentCount); 121 | return; 122 | } 123 | } 124 | 125 | db = [FMDatabase databaseWithPath:self->_path]; 126 | shouldNotifyDelegate = YES; 127 | } 128 | 129 | //This ensures that the db is opened before returning 130 | #if SQLITE_VERSION_NUMBER >= 3005000 131 | BOOL success = [db openWithFlags:self->_openFlags]; 132 | #else 133 | BOOL success = [db open]; 134 | #endif 135 | if (success) { 136 | if ([self->_delegate respondsToSelector:@selector(databasePool:shouldAddDatabaseToPool:)] && ![self->_delegate databasePool:self shouldAddDatabaseToPool:db]) { 137 | [db close]; 138 | db = 0x00; 139 | } 140 | else { 141 | //It should not get added in the pool twice if lastObject was found 142 | if (![self->_databaseOutPool containsObject:db]) { 143 | [self->_databaseOutPool addObject:db]; 144 | 145 | if (shouldNotifyDelegate && [self->_delegate respondsToSelector:@selector(databasePool:didAddDatabase:)]) { 146 | [self->_delegate databasePool:self didAddDatabase:db]; 147 | } 148 | } 149 | } 150 | } 151 | else { 152 | NSLog(@"Could not open up the database at path %@", self->_path); 153 | db = 0x00; 154 | } 155 | }]; 156 | 157 | return db; 158 | } 159 | 160 | - (NSUInteger)countOfCheckedInDatabases { 161 | 162 | __block NSUInteger count; 163 | 164 | [self executeLocked:^() { 165 | count = [self->_databaseInPool count]; 166 | }]; 167 | 168 | return count; 169 | } 170 | 171 | - (NSUInteger)countOfCheckedOutDatabases { 172 | 173 | __block NSUInteger count; 174 | 175 | [self executeLocked:^() { 176 | count = [self->_databaseOutPool count]; 177 | }]; 178 | 179 | return count; 180 | } 181 | 182 | - (NSUInteger)countOfOpenDatabases { 183 | __block NSUInteger count; 184 | 185 | [self executeLocked:^() { 186 | count = [self->_databaseOutPool count] + [self->_databaseInPool count]; 187 | }]; 188 | 189 | return count; 190 | } 191 | 192 | - (void)releaseAllDatabases { 193 | [self executeLocked:^() { 194 | [self->_databaseOutPool removeAllObjects]; 195 | [self->_databaseInPool removeAllObjects]; 196 | }]; 197 | } 198 | 199 | - (void)inDatabase:(void (^)(FMDatabase *db))block { 200 | 201 | FMDatabase *db = [self db]; 202 | 203 | block(db); 204 | 205 | [self pushDatabaseBackInPool:db]; 206 | } 207 | 208 | - (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(FMDatabase *db, BOOL *rollback))block { 209 | 210 | BOOL shouldRollback = NO; 211 | 212 | FMDatabase *db = [self db]; 213 | 214 | if (useDeferred) { 215 | [db beginDeferredTransaction]; 216 | } 217 | else { 218 | [db beginTransaction]; 219 | } 220 | 221 | 222 | block(db, &shouldRollback); 223 | 224 | if (shouldRollback) { 225 | [db rollback]; 226 | } 227 | else { 228 | [db commit]; 229 | } 230 | 231 | [self pushDatabaseBackInPool:db]; 232 | } 233 | 234 | - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { 235 | [self beginTransaction:YES withBlock:block]; 236 | } 237 | 238 | - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block { 239 | [self beginTransaction:NO withBlock:block]; 240 | } 241 | #if SQLITE_VERSION_NUMBER >= 3007000 242 | - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block { 243 | 244 | static unsigned long savePointIdx = 0; 245 | 246 | NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++]; 247 | 248 | BOOL shouldRollback = NO; 249 | 250 | FMDatabase *db = [self db]; 251 | 252 | NSError *err = 0x00; 253 | 254 | if (![db startSavePointWithName:name error:&err]) { 255 | [self pushDatabaseBackInPool:db]; 256 | return err; 257 | } 258 | 259 | block(db, &shouldRollback); 260 | 261 | if (shouldRollback) { 262 | // We need to rollback and release this savepoint to remove it 263 | [db rollbackToSavePointWithName:name error:&err]; 264 | } 265 | [db releaseSavePointWithName:name error:&err]; 266 | 267 | [self pushDatabaseBackInPool:db]; 268 | 269 | return err; 270 | } 271 | #endif 272 | 273 | @end 274 | -------------------------------------------------------------------------------- /TextUtil/Utils/Utility.m: -------------------------------------------------------------------------------- 1 | // 2 | // Utility.m 3 | // TextUtil 4 | // 5 | // Created by zx_04 on 15/8/20. 6 | // Copyright (c) 2015年 joker. All rights reserved. 7 | // 8 | 9 | #import "Utility.h" 10 | 11 | @implementation Utility 12 | 13 | + (NSMutableAttributedString *)emotionStrWithString:(NSString *)text 14 | { 15 | NSString *filePath = [[NSBundle mainBundle] pathForResource:@"emoticons" ofType:@"plist"]; 16 | NSArray *face = [NSArray arrayWithContentsOfFile:filePath]; 17 | //1、创建一个可变的属性字符串 18 | NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:text]; 19 | //2、通过正则表达式来匹配字符串 20 | NSString *regex_emoji = @"\\[[a-zA-Z0-9\\/\\u4e00-\\u9fa5]+\\]"; //匹配表情 21 | 22 | NSError *error = nil; 23 | NSRegularExpression *re = [NSRegularExpression regularExpressionWithPattern:regex_emoji options:NSRegularExpressionCaseInsensitive error:&error]; 24 | if (!re) { 25 | NSLog(@"%@", [error localizedDescription]); 26 | return attributeString; 27 | } 28 | 29 | NSArray *resultArray = [re matchesInString:text options:0 range:NSMakeRange(0, text.length)]; 30 | //3、获取所有的表情以及位置 31 | //用来存放字典,字典中存储的是图片和图片对应的位置 32 | NSMutableArray *imageArray = [NSMutableArray arrayWithCapacity:resultArray.count]; 33 | //根据匹配范围来用图片进行相应的替换 34 | for(NSTextCheckingResult *match in resultArray) { 35 | //获取数组元素中得到range 36 | NSRange range = [match range]; 37 | //获取原字符串中对应的值 38 | NSString *subStr = [text substringWithRange:range]; 39 | for (int i = 0; i < face.count; i ++) { 40 | if ([face[i][@"cht"] isEqualToString:subStr]) { 41 | //face[i][@"png"]就是我们要加载的图片 42 | //新建文字附件来存放我们的图片,iOS7才新加的对象 43 | NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init]; 44 | //给附件添加图片 45 | textAttachment.image = [UIImage imageNamed:face[i][@"png"]]; 46 | //调整一下图片的位置,如果你的图片偏上或者偏下,调整一下bounds的y值即可 47 | textAttachment.bounds = CGRectMake(0, -8, textAttachment.image.size.width, textAttachment.image.size.height); 48 | //把附件转换成可变字符串,用于替换掉源字符串中的表情文字 49 | NSAttributedString *imageStr = [NSAttributedString attributedStringWithAttachment:textAttachment]; 50 | //把图片和图片对应的位置存入字典中 51 | NSMutableDictionary *imageDic = [NSMutableDictionary dictionaryWithCapacity:2]; 52 | [imageDic setObject:imageStr forKey:@"image"]; 53 | [imageDic setObject:[NSValue valueWithRange:range] forKey:@"range"]; 54 | //把字典存入数组中 55 | [imageArray addObject:imageDic]; 56 | } 57 | } 58 | } 59 | 60 | //4、从后往前替换,否则会引起位置问题 61 | for (int i = (int)imageArray.count -1; i >= 0; i--) { 62 | NSRange range; 63 | [imageArray[i][@"range"] getValue:&range]; 64 | //进行替换 65 | [attributeString replaceCharactersInRange:range withAttributedString:imageArray[i][@"image"]]; 66 | } 67 | return attributeString; 68 | } 69 | 70 | /** 71 | * 将带有表情符的文字转换为图文混排的文字 72 | * 73 | * @param text 带表情符的文字 74 | * @param plistName 表情符与表情对应的plist文件 75 | * @param y 图片的y偏移值 76 | * 77 | * @return 转换后的文字 78 | */ 79 | + (NSMutableAttributedString *)emotionStrWithString:(NSString *)text plistName:(NSString *)plistName y:(CGFloat)y 80 | { 81 | NSString *filePath = [[NSBundle mainBundle] pathForResource:plistName ofType:nil]; 82 | NSArray *face = [NSArray arrayWithContentsOfFile:filePath]; 83 | //1、创建一个可变的属性字符串 84 | NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:text]; 85 | //2、通过正则表达式来匹配字符串 86 | NSString *regex_emoji = @"\\[[a-zA-Z0-9\\/\\u4e00-\\u9fa5]+\\]"; //匹配表情 87 | 88 | NSError *error = nil; 89 | NSRegularExpression *re = [NSRegularExpression regularExpressionWithPattern:regex_emoji options:NSRegularExpressionCaseInsensitive error:&error]; 90 | if (!re) { 91 | NSLog(@"%@", [error localizedDescription]); 92 | return attributeString; 93 | } 94 | 95 | NSArray *resultArray = [re matchesInString:text options:0 range:NSMakeRange(0, text.length)]; 96 | //3、获取所有的表情以及位置 97 | //用来存放字典,字典中存储的是图片和图片对应的位置 98 | NSMutableArray *imageArray = [NSMutableArray arrayWithCapacity:resultArray.count]; 99 | //根据匹配范围来用图片进行相应的替换 100 | for(NSTextCheckingResult *match in resultArray) { 101 | //获取数组元素中得到range 102 | NSRange range = [match range]; 103 | //获取原字符串中对应的值 104 | NSString *subStr = [text substringWithRange:range]; 105 | for (int i = 0; i < face.count; i ++) { 106 | if ([face[i][@"cht"] isEqualToString:subStr]) { 107 | //face[i][@"png"]就是我们要加载的图片 108 | //新建文字附件来存放我们的图片,iOS7才新加的对象 109 | NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init]; 110 | //给附件添加图片 111 | textAttachment.image = [UIImage imageNamed:face[i][@"png"]]; 112 | //调整一下图片的位置,如果你的图片偏上或者偏下,调整一下bounds的y值即可 113 | textAttachment.bounds = CGRectMake(0, y, textAttachment.image.size.width, textAttachment.image.size.height); 114 | //把附件转换成可变字符串,用于替换掉源字符串中的表情文字 115 | NSAttributedString *imageStr = [NSAttributedString attributedStringWithAttachment:textAttachment]; 116 | //把图片和图片对应的位置存入字典中 117 | NSMutableDictionary *imageDic = [NSMutableDictionary dictionaryWithCapacity:2]; 118 | [imageDic setObject:imageStr forKey:@"image"]; 119 | [imageDic setObject:[NSValue valueWithRange:range] forKey:@"range"]; 120 | //把字典存入数组中 121 | [imageArray addObject:imageDic]; 122 | } 123 | } 124 | } 125 | 126 | //4、从后往前替换,否则会引起位置问题 127 | for (int i = (int)imageArray.count -1; i >= 0; i--) { 128 | NSRange range; 129 | [imageArray[i][@"range"] getValue:&range]; 130 | //进行替换 131 | [attributeString replaceCharactersInRange:range withAttributedString:imageArray[i][@"image"]]; 132 | } 133 | return attributeString; 134 | } 135 | 136 | + (NSMutableAttributedString *)exchangeString:(NSString *)string withText:(NSString *)text imageName:(NSString *)imageName 137 | { 138 | //1、创建一个可变的属性字符串 139 | NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:text]; 140 | 141 | //2、匹配字符串 142 | NSError *error = nil; 143 | NSRegularExpression *re = [NSRegularExpression regularExpressionWithPattern:string options:NSRegularExpressionCaseInsensitive error:&error]; 144 | if (!re) { 145 | NSLog(@"%@", [error localizedDescription]); 146 | return attributeString; 147 | } 148 | 149 | NSArray *resultArray = [re matchesInString:text options:0 range:NSMakeRange(0, text.length)]; 150 | //3、获取所有的图片以及位置 151 | //用来存放字典,字典中存储的是图片和图片对应的位置 152 | NSMutableArray *imageArray = [NSMutableArray arrayWithCapacity:resultArray.count]; 153 | //根据匹配范围来用图片进行相应的替换 154 | for(NSTextCheckingResult *match in resultArray) { 155 | //获取数组元素中得到range 156 | NSRange range = [match range]; 157 | //新建文字附件来存放我们的图片(iOS7才新加的对象) 158 | NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init]; 159 | //给附件添加图片 160 | textAttachment.image = [UIImage imageNamed:imageName]; 161 | //修改一下图片的位置,y为负值,表示向下移动 162 | textAttachment.bounds = CGRectMake(0, -2, textAttachment.image.size.width, textAttachment.image.size.height); 163 | //把附件转换成可变字符串,用于替换掉源字符串中的表情文字 164 | NSAttributedString *imageStr = [NSAttributedString attributedStringWithAttachment:textAttachment]; 165 | //把图片和图片对应的位置存入字典中 166 | NSMutableDictionary *imageDic = [NSMutableDictionary dictionaryWithCapacity:2]; 167 | [imageDic setObject:imageStr forKey:@"image"]; 168 | [imageDic setObject:[NSValue valueWithRange:range] forKey:@"range"]; 169 | //把字典存入数组中 170 | [imageArray addObject:imageDic]; 171 | } 172 | 173 | //4、从后往前替换,否则会引起位置问题 174 | for (int i = (int)imageArray.count -1; i >= 0; i--) { 175 | NSRange range; 176 | [imageArray[i][@"range"] getValue:&range]; 177 | //进行替换 178 | [attributeString replaceCharactersInRange:range withAttributedString:imageArray[i][@"image"]]; 179 | } 180 | 181 | return attributeString; 182 | } 183 | 184 | @end 185 | -------------------------------------------------------------------------------- /TextUtil/Discover/Views/DynamicView.m: -------------------------------------------------------------------------------- 1 | // 2 | // DynamicView.m 3 | // TextUtil 4 | // 5 | // Created by zx_04 on 15/8/19. 6 | // Copyright (c) 2015年 joker. All rights reserved. 7 | // 8 | 9 | #import "DynamicView.h" 10 | #import "Utility.h" 11 | 12 | @interface DynamicView () 13 | 14 | /** 正文的文字 */ 15 | @property (nonatomic, retain) UILabel *contentLabel; 16 | /** 图片视图数组 */ 17 | @property (nonatomic, retain) NSMutableArray *imageViews; 18 | 19 | @property (nonatomic, retain) UIButton *videoBtn; 20 | 21 | @end 22 | 23 | @implementation DynamicView 24 | 25 | - (instancetype)initWithFrame:(CGRect)frame 26 | { 27 | self = [super initWithFrame:frame]; 28 | if (self) { 29 | [self initSubViews]; 30 | } 31 | return self; 32 | } 33 | 34 | /** 初始化子控件 */ 35 | - (void)initSubViews 36 | { 37 | //添加正文 38 | _contentLabel = [[UILabel alloc] initWithFrame:CGRectZero]; 39 | _contentLabel.font = kContentFont; 40 | _contentLabel.textColor = [UIColor blackColor]; 41 | _contentLabel.numberOfLines = 0; 42 | [self addSubview:_contentLabel]; 43 | 44 | _imageViews = [[NSMutableArray alloc] initWithCapacity:10]; 45 | for (int i = 0; i < 9; i++) { 46 | UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectZero]; 47 | imageView.contentMode = UIViewContentModeScaleAspectFill; 48 | imageView.clipsToBounds = YES; 49 | imageView.tag = 2015 + i; 50 | [self addSubview:imageView]; 51 | [_imageViews addObject:imageView]; 52 | } 53 | 54 | _videoBtn = [[UIButton alloc] initWithFrame:CGRectZero]; 55 | [_videoBtn setImage:[UIImage imageNamed:@"chatgroup_video_play_btbg"] forState:UIControlStateNormal]; 56 | // [_videoBtn addTarget:self action:@selector(videoClick:) forControlEvents:UIControlEventTouchUpInside]; 57 | 58 | [self addSubview:_videoBtn]; 59 | } 60 | 61 | - (void)setDynamic:(Dynamic *)dynamic 62 | { 63 | if (_dynamic != dynamic) { 64 | _dynamic = dynamic; 65 | } 66 | 67 | _contentLabel.hidden = YES; 68 | for (UIImageView *imageView in _imageViews) { 69 | imageView.hidden = YES; 70 | } 71 | _videoBtn.hidden = YES; 72 | 73 | if (_dynamic.type == 0) { //纯文字 74 | NSMutableAttributedString *content = [Utility emotionStrWithString:_dynamic.text]; 75 | [content addAttribute:NSFontAttributeName value:kContentFont range:NSMakeRange(0, content.length)]; 76 | CGSize maxSize = CGSizeMake(kDynamicWidth, MAXFLOAT); 77 | CGSize attrStrSize = [content boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin context:nil].size; 78 | _contentLabel.frame = CGRectMake(0, 0, attrStrSize.width, attrStrSize.height); 79 | _contentLabel.attributedText = content; 80 | _contentLabel.hidden = NO; 81 | } else if (_dynamic.type == 1) { //带图片 82 | CGFloat contentHeight = 0; 83 | if (_dynamic.text.length <= 0) {//不存在文字,肯定是纯图片 84 | _contentLabel.frame = CGRectZero; 85 | _contentLabel.hidden = YES; 86 | } else { //文字+图片 87 | NSMutableAttributedString *content = [Utility emotionStrWithString:_dynamic.text]; 88 | [content addAttribute:NSFontAttributeName value:kContentFont range:NSMakeRange(0, content.length)]; 89 | CGSize maxSize = CGSizeMake(kDynamicWidth, MAXFLOAT); 90 | CGSize attrStrSize = [content boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin context:nil].size; 91 | _contentLabel.frame = CGRectMake(0, 0, attrStrSize.width, attrStrSize.height); 92 | _contentLabel.attributedText = content; 93 | _contentLabel.hidden = NO; 94 | contentHeight = attrStrSize.height+10; 95 | } 96 | 97 | for (int i = 0; i < _dynamic.imageCount; i++) { 98 | if (i > 8) { 99 | break; 100 | } 101 | int rowNum = i/3; 102 | int colNum = i%3; 103 | CGFloat imageX = colNum*(kImageWidth+kImagePadding); 104 | CGFloat imageY = contentHeight + rowNum*(kImageWidth+kImagePadding); 105 | CGRect frame = CGRectMake(imageX,imageY, kImageWidth, kImageWidth); 106 | if (_dynamic.imageCount == 1) { 107 | frame = CGRectMake(0, contentHeight, kSingleImageWidth, kSingleImageWidth-40); 108 | } 109 | UIImageView *imageView = [_imageViews objectAtIndex:i]; 110 | imageView.hidden = NO; 111 | imageView.frame = frame; 112 | NSString *imageName = [NSString stringWithFormat:@"image_0%d.jpg",i+1]; 113 | imageView.image = [UIImage imageNamed:imageName]; 114 | } 115 | 116 | } else if (_dynamic.type == 2) { //小视频 117 | CGFloat contentHeight = 0; 118 | if (_dynamic.text.length <= 0) {//不存在文字,肯定是纯图片 119 | _contentLabel.frame = CGRectZero; 120 | _contentLabel.hidden = YES; 121 | } else { //文字+图片 122 | NSMutableAttributedString *content = [Utility emotionStrWithString:_dynamic.text]; 123 | [content addAttribute:NSFontAttributeName value:kContentFont range:NSMakeRange(0, content.length)]; 124 | CGSize maxSize = CGSizeMake(kDynamicWidth, MAXFLOAT); 125 | CGSize attrStrSize = [content boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin context:nil].size; 126 | _contentLabel.frame = CGRectMake(0, 0, attrStrSize.width, attrStrSize.height); 127 | _contentLabel.attributedText = content; 128 | _contentLabel.hidden = NO; 129 | contentHeight = attrStrSize.height+10; 130 | } 131 | 132 | _videoBtn.hidden = NO; 133 | _videoBtn.frame = CGRectMake(0, contentHeight, kSingleImageWidth, kSingleImageWidth-40); 134 | [_videoBtn setBackgroundImage:[UIImage imageNamed:@"bb_default_picture_bg.png"] forState:UIControlStateNormal]; 135 | } 136 | } 137 | 138 | 139 | + (CGFloat)getHeightWithModel:(Dynamic *)dynamic 140 | { 141 | if (dynamic.type == 0) { //纯文字 142 | NSMutableAttributedString *content = [Utility emotionStrWithString:dynamic.text]; 143 | [content addAttribute:NSFontAttributeName value:kContentFont range:NSMakeRange(0, content.length)]; 144 | CGSize maxSize = CGSizeMake(kDynamicWidth, MAXFLOAT); 145 | CGSize attrStrSize = [content boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin context:nil].size; 146 | return attrStrSize.height; 147 | } else if (dynamic.type == 1) { //附带图片 148 | CGFloat height = 0; 149 | if (dynamic.text.length > 0) {//文字 150 | NSMutableAttributedString *content = [Utility emotionStrWithString:dynamic.text]; 151 | [content addAttribute:NSFontAttributeName value:kContentFont range:NSMakeRange(0, content.length)]; 152 | CGSize maxSize = CGSizeMake(kDynamicWidth, MAXFLOAT); 153 | CGSize attrStrSize = [content boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin context:nil].size; 154 | height += attrStrSize.height; 155 | } 156 | int imageCount = dynamic.imageCount; 157 | if (imageCount == 0) { 158 | 159 | } else if (imageCount == 1) { 160 | height += kSingleImageWidth-40+10; 161 | } else if (imageCount < 4) { 162 | height += (kImageWidth+10); 163 | } else if (imageCount < 7) { 164 | height += (kImageWidth*2 + kImagePadding+10); 165 | } else { 166 | height += (kImageWidth*3 + kImagePadding*2+10); 167 | } 168 | return height; 169 | } else if (dynamic.type == 3){ 170 | CGFloat height = 0; 171 | if (dynamic.text.length <= 0) {//不存在文字,肯定是纯视频 172 | 173 | } else { //文字+视频 174 | NSMutableAttributedString *content = [Utility emotionStrWithString:dynamic.text]; 175 | [content addAttribute:NSFontAttributeName value:kContentFont range:NSMakeRange(0, content.length)]; 176 | CGSize maxSize = CGSizeMake(kDynamicWidth, MAXFLOAT); 177 | CGSize attrStrSize = [content boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin context:nil].size; 178 | height += (attrStrSize.height+10); 179 | } 180 | 181 | height += (kSingleImageWidth-40); 182 | return height; 183 | } 184 | 185 | return 0; 186 | } 187 | 188 | @end 189 | -------------------------------------------------------------------------------- /TextUtil/OpenSources/FMDB/FMDatabaseAdditions.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMDatabaseAdditions.h 3 | // fmdb 4 | // 5 | // Created by August Mueller on 10/30/05. 6 | // Copyright 2005 Flying Meat Inc.. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "FMDatabase.h" 11 | 12 | 13 | /** Category of additions for `` class. 14 | 15 | ### See also 16 | 17 | - `` 18 | */ 19 | 20 | @interface FMDatabase (FMDatabaseAdditions) 21 | 22 | ///---------------------------------------- 23 | /// @name Return results of SQL to variable 24 | ///---------------------------------------- 25 | 26 | /** Return `int` value for query 27 | 28 | @param query The SQL query to be performed. 29 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 30 | 31 | @return `int` value. 32 | 33 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. 34 | */ 35 | 36 | - (int)intForQuery:(NSString*)query, ...; 37 | 38 | /** Return `long` value for query 39 | 40 | @param query The SQL query to be performed. 41 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 42 | 43 | @return `long` value. 44 | 45 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. 46 | */ 47 | 48 | - (long)longForQuery:(NSString*)query, ...; 49 | 50 | /** Return `BOOL` value for query 51 | 52 | @param query The SQL query to be performed. 53 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 54 | 55 | @return `BOOL` value. 56 | 57 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. 58 | */ 59 | 60 | - (BOOL)boolForQuery:(NSString*)query, ...; 61 | 62 | /** Return `double` value for query 63 | 64 | @param query The SQL query to be performed. 65 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 66 | 67 | @return `double` value. 68 | 69 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. 70 | */ 71 | 72 | - (double)doubleForQuery:(NSString*)query, ...; 73 | 74 | /** Return `NSString` value for query 75 | 76 | @param query The SQL query to be performed. 77 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 78 | 79 | @return `NSString` value. 80 | 81 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. 82 | */ 83 | 84 | - (NSString*)stringForQuery:(NSString*)query, ...; 85 | 86 | /** Return `NSData` value for query 87 | 88 | @param query The SQL query to be performed. 89 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 90 | 91 | @return `NSData` value. 92 | 93 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. 94 | */ 95 | 96 | - (NSData*)dataForQuery:(NSString*)query, ...; 97 | 98 | /** Return `NSDate` value for query 99 | 100 | @param query The SQL query to be performed. 101 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 102 | 103 | @return `NSDate` value. 104 | 105 | @note To use this method from Swift, you must include `FMDatabaseAdditionsVariadic.swift` in your project. 106 | */ 107 | 108 | - (NSDate*)dateForQuery:(NSString*)query, ...; 109 | 110 | 111 | // Notice that there's no dataNoCopyForQuery:. 112 | // That would be a bad idea, because we close out the result set, and then what 113 | // happens to the data that we just didn't copy? Who knows, not I. 114 | 115 | 116 | ///-------------------------------- 117 | /// @name Schema related operations 118 | ///-------------------------------- 119 | 120 | /** Does table exist in database? 121 | 122 | @param tableName The name of the table being looked for. 123 | 124 | @return `YES` if table found; `NO` if not found. 125 | */ 126 | 127 | - (BOOL)tableExists:(NSString*)tableName; 128 | 129 | /** The schema of the database. 130 | 131 | This will be the schema for the entire database. For each entity, each row of the result set will include the following fields: 132 | 133 | - `type` - The type of entity (e.g. table, index, view, or trigger) 134 | - `name` - The name of the object 135 | - `tbl_name` - The name of the table to which the object references 136 | - `rootpage` - The page number of the root b-tree page for tables and indices 137 | - `sql` - The SQL that created the entity 138 | 139 | @return `FMResultSet` of schema; `nil` on error. 140 | 141 | @see [SQLite File Format](http://www.sqlite.org/fileformat.html) 142 | */ 143 | 144 | - (FMResultSet*)getSchema; 145 | 146 | /** The schema of the database. 147 | 148 | This will be the schema for a particular table as report by SQLite `PRAGMA`, for example: 149 | 150 | PRAGMA table_info('employees') 151 | 152 | This will report: 153 | 154 | - `cid` - The column ID number 155 | - `name` - The name of the column 156 | - `type` - The data type specified for the column 157 | - `notnull` - whether the field is defined as NOT NULL (i.e. values required) 158 | - `dflt_value` - The default value for the column 159 | - `pk` - Whether the field is part of the primary key of the table 160 | 161 | @param tableName The name of the table for whom the schema will be returned. 162 | 163 | @return `FMResultSet` of schema; `nil` on error. 164 | 165 | @see [table_info](http://www.sqlite.org/pragma.html#pragma_table_info) 166 | */ 167 | 168 | - (FMResultSet*)getTableSchema:(NSString*)tableName; 169 | 170 | /** Test to see if particular column exists for particular table in database 171 | 172 | @param columnName The name of the column. 173 | 174 | @param tableName The name of the table. 175 | 176 | @return `YES` if column exists in table in question; `NO` otherwise. 177 | */ 178 | 179 | - (BOOL)columnExists:(NSString*)columnName inTableWithName:(NSString*)tableName; 180 | 181 | /** Test to see if particular column exists for particular table in database 182 | 183 | @param columnName The name of the column. 184 | 185 | @param tableName The name of the table. 186 | 187 | @return `YES` if column exists in table in question; `NO` otherwise. 188 | 189 | @see columnExists:inTableWithName: 190 | 191 | @warning Deprecated - use `` instead. 192 | */ 193 | 194 | - (BOOL)columnExists:(NSString*)tableName columnName:(NSString*)columnName __attribute__ ((deprecated)); 195 | 196 | 197 | /** Validate SQL statement 198 | 199 | This validates SQL statement by performing `sqlite3_prepare_v2`, but not returning the results, but instead immediately calling `sqlite3_finalize`. 200 | 201 | @param sql The SQL statement being validated. 202 | 203 | @param error This is a pointer to a `NSError` object that will receive the autoreleased `NSError` object if there was any error. If this is `nil`, no `NSError` result will be returned. 204 | 205 | @return `YES` if validation succeeded without incident; `NO` otherwise. 206 | 207 | */ 208 | 209 | - (BOOL)validateSQL:(NSString*)sql error:(NSError**)error; 210 | 211 | 212 | #if SQLITE_VERSION_NUMBER >= 3007017 213 | 214 | ///----------------------------------- 215 | /// @name Application identifier tasks 216 | ///----------------------------------- 217 | 218 | /** Retrieve application ID 219 | 220 | @return The `uint32_t` numeric value of the application ID. 221 | 222 | @see setApplicationID: 223 | */ 224 | 225 | - (uint32_t)applicationID; 226 | 227 | /** Set the application ID 228 | 229 | @param appID The `uint32_t` numeric value of the application ID. 230 | 231 | @see applicationID 232 | */ 233 | 234 | - (void)setApplicationID:(uint32_t)appID; 235 | 236 | #if TARGET_OS_MAC && !TARGET_OS_IPHONE 237 | /** Retrieve application ID string 238 | 239 | @return The `NSString` value of the application ID. 240 | 241 | @see setApplicationIDString: 242 | */ 243 | 244 | 245 | - (NSString*)applicationIDString; 246 | 247 | /** Set the application ID string 248 | 249 | @param string The `NSString` value of the application ID. 250 | 251 | @see applicationIDString 252 | */ 253 | 254 | - (void)setApplicationIDString:(NSString*)string; 255 | #endif 256 | 257 | #endif 258 | 259 | ///----------------------------------- 260 | /// @name user version identifier tasks 261 | ///----------------------------------- 262 | 263 | /** Retrieve user version 264 | 265 | @return The `uint32_t` numeric value of the user version. 266 | 267 | @see setUserVersion: 268 | */ 269 | 270 | - (uint32_t)userVersion; 271 | 272 | /** Set the user-version 273 | 274 | @param version The `uint32_t` numeric value of the user version. 275 | 276 | @see userVersion 277 | */ 278 | 279 | - (void)setUserVersion:(uint32_t)version; 280 | 281 | @end 282 | -------------------------------------------------------------------------------- /TextUtil/Discover/Views/DynamicCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // DynamicCell.m 3 | // TextUtil 4 | // 5 | // Created by zx_04 on 15/8/19. 6 | // Copyright (c) 2015年 joker. All rights reserved. 7 | // 8 | 9 | #import "DynamicCell.h" 10 | #import "DynamicView.h" 11 | 12 | #import "Dynamic.h" 13 | #import "Utility.h" 14 | 15 | @interface DynamicCell () 16 | 17 | @property (nonatomic, retain) UIImageView *faceImageView; 18 | @property (nonatomic, retain) UILabel *nameLabel; 19 | @property (nonatomic, retain) UILabel *locationLabel; 20 | /** 板报内容视图 */ 21 | @property (nonatomic, retain) DynamicView *dynamicView; 22 | /** 操作视图 */ 23 | @property (nonatomic, retain) UIView *optionView; 24 | /** 分隔线 */ 25 | @property (nonatomic, retain) UIView *lineView; 26 | /** 点赞视图 */ 27 | @property (nonatomic, retain) UILabel *praiseLabel; 28 | 29 | @end 30 | 31 | @implementation DynamicCell 32 | 33 | - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier 34 | { 35 | self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; 36 | if (self) { 37 | [self setUpSubViews]; 38 | } 39 | return self; 40 | } 41 | 42 | - (void)setUpSubViews 43 | { 44 | //头像视图 45 | _faceImageView = [[UIImageView alloc] init]; 46 | _faceImageView.layer.cornerRadius = kFaceWidth/2; 47 | _faceImageView.layer.masksToBounds = YES; 48 | _faceImageView.userInteractionEnabled = YES; 49 | UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(faceClick)]; 50 | [_faceImageView addGestureRecognizer:tapGesture]; 51 | 52 | [self.contentView addSubview:_faceImageView]; 53 | //名字视图 54 | _nameLabel = [[UILabel alloc] init]; 55 | _nameLabel.textColor = nameColor; 56 | [self.contentView addSubview:_nameLabel]; 57 | 58 | //位置视图 59 | _locationLabel = [[UILabel alloc] init]; 60 | _locationLabel.textColor = customGrayColor; 61 | _locationLabel.font = [UIFont systemFontOfSize:13.0f]; 62 | [self.contentView addSubview:_locationLabel]; 63 | 64 | //板报正文视图 65 | _dynamicView = [[DynamicView alloc] initWithFrame:CGRectZero]; 66 | // _dynamicView.delegate = self; 67 | [self.contentView addSubview:_dynamicView]; 68 | 69 | //操作控件视图 70 | [self initOptionView]; 71 | 72 | //分隔线 73 | _lineView = [[UIView alloc] initWithFrame:CGRectZero]; 74 | _lineView.backgroundColor = TABLEVIEW_BORDER_COLOR; 75 | [self.contentView addSubview:_lineView]; 76 | 77 | //点赞人员视图 78 | _praiseLabel = [[UILabel alloc] init]; 79 | _praiseLabel.textColor = customGrayColor; 80 | _praiseLabel.font = [UIFont systemFontOfSize:14.0f]; 81 | _praiseLabel.numberOfLines = 0; 82 | [self.contentView addSubview:_praiseLabel]; 83 | } 84 | 85 | /** 初始化操作控件视图 */ 86 | - (void)initOptionView 87 | { 88 | _optionView = [[UIView alloc] initWithFrame:CGRectZero]; 89 | [self.contentView addSubview:_optionView]; 90 | 91 | CGFloat btnWidth = 70; 92 | //点赞按钮 93 | UIButton *praiseBtn = [[UIButton alloc] initWithFrame:CGRectMake(kWidth-65-btnWidth*3, 0, btnWidth, kOptionHeight)]; 94 | praiseBtn.tag = 110; 95 | [praiseBtn setImage:[UIImage imageNamed:@"dynamic_love"] forState:UIControlStateNormal]; 96 | praiseBtn.titleLabel.font =[UIFont systemFontOfSize:14.0]; 97 | [praiseBtn setTitleColor:customGrayColor forState:UIControlStateNormal]; 98 | [praiseBtn addTarget:self action:@selector(praiseClick:) forControlEvents:UIControlEventTouchUpInside]; 99 | [_optionView addSubview:praiseBtn]; 100 | 101 | UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(CGRectGetMaxX(praiseBtn.frame), kPadding*0.75, 1, kOptionHeight-kPadding*1.5)]; 102 | lineView.backgroundColor = [UIColor lightGrayColor]; 103 | [_optionView addSubview:lineView]; 104 | 105 | //评论按钮 106 | UIButton *cmdBtn = [[UIButton alloc] initWithFrame:CGRectMake(kWidth-65-btnWidth*2, 0, btnWidth, kOptionHeight)]; 107 | cmdBtn.tag = 111; 108 | [cmdBtn setImage:[UIImage imageNamed:@"dynamic_comment"] forState:UIControlStateNormal]; 109 | [cmdBtn setTitleColor:customGrayColor forState:UIControlStateNormal]; 110 | [cmdBtn setTitle:@" 评论" forState:UIControlStateNormal]; 111 | cmdBtn.titleLabel.font =[UIFont systemFontOfSize:14.0]; 112 | // [cmdBtn addTarget:self action:@selector(cmtClick:) forControlEvents:UIControlEventTouchUpInside]; 113 | 114 | [_optionView addSubview:cmdBtn]; 115 | 116 | _lineView = [[UIView alloc] initWithFrame:CGRectMake(CGRectGetMaxX(cmdBtn.frame), kPadding*0.75, 1, kOptionHeight-kPadding*1.5)]; 117 | _lineView.backgroundColor = [UIColor lightGrayColor]; 118 | [_optionView addSubview:_lineView]; 119 | 120 | //收藏按钮 121 | UIButton *collectBtn = [[UIButton alloc] initWithFrame:CGRectMake(kWidth-65-btnWidth, 0, btnWidth, kOptionHeight)]; 122 | collectBtn.tag = 112; 123 | [collectBtn setImage:[UIImage imageNamed:@"dynamic_collect"] forState:UIControlStateNormal]; 124 | [collectBtn setTitleColor:customGrayColor forState:UIControlStateNormal]; 125 | [collectBtn setTitle:@" 收藏" forState:UIControlStateNormal]; 126 | collectBtn.titleLabel.font =[UIFont systemFontOfSize:14.0]; 127 | // [collectBtn addTarget:self action:@selector(collectClick:) forControlEvents:UIControlEventTouchUpInside]; 128 | [_optionView addSubview:collectBtn]; 129 | 130 | } 131 | 132 | - (void)faceClick 133 | { 134 | NSLog(@"%s",__func__); 135 | } 136 | 137 | - (void)praiseClick:(UIButton *)btn 138 | { 139 | 140 | } 141 | 142 | - (void)setDynamic:(Dynamic *)dynamic 143 | { 144 | if (_dynamic != dynamic) { 145 | _dynamic = dynamic; 146 | } 147 | 148 | _faceImageView.frame = CGRectMake(kPadding, kPadding, kFaceWidth, kFaceWidth); 149 | _faceImageView.image = [UIImage imageNamed:@"header_wechat"]; 150 | 151 | _nameLabel.frame = CGRectMake(_faceImageView.right+kPadding, _faceImageView.top, kWidth-kFaceWidth-kPadding*3, 20); 152 | _nameLabel.text = @"路人甲"; 153 | NSString *location = [NSString stringWithFormat:@"%@ | %@",_dynamic.location,_dynamic.createTime]; 154 | 155 | _locationLabel.frame = CGRectMake(_nameLabel.left, _nameLabel.bottom+kPadding, _nameLabel.width, 15); 156 | _locationLabel.text = location; 157 | 158 | CGFloat height = [DynamicView getHeightWithModel:_dynamic]; 159 | _dynamicView.frame = CGRectMake(_nameLabel.left, _faceImageView.bottom+kPadding, kDynamicWidth, height); 160 | _dynamicView.dynamic = _dynamic; 161 | 162 | _optionView.frame = CGRectMake(_nameLabel.left, _dynamicView.bottom+kPadding, kWidth-65, kOptionHeight); 163 | //赞 164 | UIButton *praiseBtn = (UIButton *)[_optionView viewWithTag:110]; 165 | NSString *praiseCount = [NSString stringWithFormat:@" %d",_dynamic.praiseCount]; 166 | [praiseBtn setTitle:praiseCount forState:UIControlStateNormal]; 167 | 168 | // NSDictionary *attributes = @{NSFontAttributeName:[UIFont systemFontOfSize:14.0],NSForegroundColorAttributeName:nameColor}; 169 | NSDictionary *attributes = @{NSFontAttributeName:[UIFont systemFontOfSize:14.0]}; 170 | NSString *praiseStr = @"路人甲、路人乙"; 171 | NSString *praiseInfo = [NSString stringWithFormat:@"<点赞> %@",praiseStr]; 172 | NSDictionary *attributesForAll = @{NSFontAttributeName:[UIFont systemFontOfSize:14.0],NSForegroundColorAttributeName:[UIColor grayColor]}; 173 | NSMutableAttributedString *attrStr = [Utility exchangeString:@"<点赞>" withText:praiseInfo imageName:@"dynamic_love_blue"]; //dynamic_love_blue 174 | [attrStr addAttributes:attributesForAll range:NSMakeRange(0, attrStr.length)]; 175 | NSRange darkRange =[attrStr.string rangeOfString:praiseStr]; 176 | [attrStr addAttributes:attributes range:darkRange]; 177 | 178 | CGSize labelSize = [attrStr boundingRectWithSize:CGSizeMake(kWidth-65-kPadding, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin context:nil].size; 179 | _praiseLabel.attributedText = attrStr; 180 | _praiseLabel.frame = CGRectMake(_nameLabel.left, _optionView.bottom + kPadding, labelSize.width, labelSize.height); 181 | 182 | } 183 | 184 | 185 | #pragma mark - Class method 186 | + (instancetype)cellWithTableView:(UITableView *)tableView 187 | { 188 | static NSString *identifier = @"dynamicCell"; 189 | DynamicCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; 190 | if (cell == nil) { 191 | cell = [[DynamicCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier]; 192 | cell.selectionStyle = UITableViewCellSelectionStyleNone; 193 | } 194 | return cell; 195 | } 196 | 197 | + (CGFloat)heightOfCellWithModel:(Dynamic *)dynamic 198 | { 199 | CGFloat height = 0; 200 | //头像高度 201 | height += (kPadding+kFaceWidth); 202 | //计算正文高度 203 | height += (kPadding +[DynamicView getHeightWithModel:dynamic]); 204 | //控件视图高度 205 | height += (kPadding+kOptionHeight); 206 | //点赞视图高度 207 | CGSize praiseSize = [self getHeightOfPraiseView:dynamic]; 208 | height += (kPadding + praiseSize.height); 209 | 210 | height += kPadding+7; 211 | 212 | return height; 213 | } 214 | 215 | + (CGSize)getHeightOfPraiseView:(Dynamic *)dynamic 216 | { 217 | NSString *praiseStr = @"路人ABC"; 218 | NSDictionary *attributes = @{NSFontAttributeName:[UIFont systemFontOfSize:14.0],NSForegroundColorAttributeName:nameColor}; 219 | 220 | NSString *praiseInfo = [NSString stringWithFormat:@"<点赞> %@",praiseStr]; 221 | NSDictionary *attributesForAll = @{NSFontAttributeName:[UIFont systemFontOfSize:14.0],NSForegroundColorAttributeName:[UIColor grayColor]}; 222 | NSMutableAttributedString *attrStr = [Utility exchangeString:@"<点赞>" withText:praiseInfo imageName:@"dynamic_love_blue"]; 223 | [attrStr addAttributes:attributesForAll range:NSMakeRange(0, attrStr.length)]; 224 | NSRange darkRange =[attrStr.string rangeOfString:praiseStr]; 225 | [attrStr addAttributes:attributes range:darkRange]; 226 | 227 | CGSize labelSize = [attrStr boundingRectWithSize:CGSizeMake(kWidth-65-kPadding, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin context:nil].size; 228 | return labelSize; 229 | } 230 | 231 | @end 232 | -------------------------------------------------------------------------------- /TextUtil/OpenSources/FMDB/FMResultSet.m: -------------------------------------------------------------------------------- 1 | #import "FMResultSet.h" 2 | #import "FMDatabase.h" 3 | #import "unistd.h" 4 | 5 | @interface FMDatabase () 6 | - (void)resultSetDidClose:(FMResultSet *)resultSet; 7 | @end 8 | 9 | 10 | @implementation FMResultSet 11 | @synthesize query=_query; 12 | @synthesize statement=_statement; 13 | 14 | + (instancetype)resultSetWithStatement:(FMStatement *)statement usingParentDatabase:(FMDatabase*)aDB { 15 | 16 | FMResultSet *rs = [[FMResultSet alloc] init]; 17 | 18 | [rs setStatement:statement]; 19 | [rs setParentDB:aDB]; 20 | 21 | NSParameterAssert(![statement inUse]); 22 | [statement setInUse:YES]; // weak reference 23 | 24 | return FMDBReturnAutoreleased(rs); 25 | } 26 | 27 | - (void)finalize { 28 | [self close]; 29 | [super finalize]; 30 | } 31 | 32 | - (void)dealloc { 33 | [self close]; 34 | 35 | FMDBRelease(_query); 36 | _query = nil; 37 | 38 | FMDBRelease(_columnNameToIndexMap); 39 | _columnNameToIndexMap = nil; 40 | 41 | #if ! __has_feature(objc_arc) 42 | [super dealloc]; 43 | #endif 44 | } 45 | 46 | - (void)close { 47 | [_statement reset]; 48 | FMDBRelease(_statement); 49 | _statement = nil; 50 | 51 | // we don't need this anymore... (i think) 52 | //[_parentDB setInUse:NO]; 53 | [_parentDB resultSetDidClose:self]; 54 | _parentDB = nil; 55 | } 56 | 57 | - (int)columnCount { 58 | return sqlite3_column_count([_statement statement]); 59 | } 60 | 61 | - (NSMutableDictionary *)columnNameToIndexMap { 62 | if (!_columnNameToIndexMap) { 63 | int columnCount = sqlite3_column_count([_statement statement]); 64 | _columnNameToIndexMap = [[NSMutableDictionary alloc] initWithCapacity:(NSUInteger)columnCount]; 65 | int columnIdx = 0; 66 | for (columnIdx = 0; columnIdx < columnCount; columnIdx++) { 67 | [_columnNameToIndexMap setObject:[NSNumber numberWithInt:columnIdx] 68 | forKey:[[NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)] lowercaseString]]; 69 | } 70 | } 71 | return _columnNameToIndexMap; 72 | } 73 | 74 | - (void)kvcMagic:(id)object { 75 | 76 | int columnCount = sqlite3_column_count([_statement statement]); 77 | 78 | int columnIdx = 0; 79 | for (columnIdx = 0; columnIdx < columnCount; columnIdx++) { 80 | 81 | const char *c = (const char *)sqlite3_column_text([_statement statement], columnIdx); 82 | 83 | // check for a null row 84 | if (c) { 85 | NSString *s = [NSString stringWithUTF8String:c]; 86 | 87 | [object setValue:s forKey:[NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)]]; 88 | } 89 | } 90 | } 91 | 92 | #pragma clang diagnostic push 93 | #pragma clang diagnostic ignored "-Wdeprecated-implementations" 94 | 95 | - (NSDictionary*)resultDict { 96 | 97 | NSUInteger num_cols = (NSUInteger)sqlite3_data_count([_statement statement]); 98 | 99 | if (num_cols > 0) { 100 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:num_cols]; 101 | 102 | NSEnumerator *columnNames = [[self columnNameToIndexMap] keyEnumerator]; 103 | NSString *columnName = nil; 104 | while ((columnName = [columnNames nextObject])) { 105 | id objectValue = [self objectForColumnName:columnName]; 106 | [dict setObject:objectValue forKey:columnName]; 107 | } 108 | 109 | return FMDBReturnAutoreleased([dict copy]); 110 | } 111 | else { 112 | NSLog(@"Warning: There seem to be no columns in this set."); 113 | } 114 | 115 | return nil; 116 | } 117 | 118 | #pragma clang diagnostic pop 119 | 120 | - (NSDictionary*)resultDictionary { 121 | 122 | NSUInteger num_cols = (NSUInteger)sqlite3_data_count([_statement statement]); 123 | 124 | if (num_cols > 0) { 125 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:num_cols]; 126 | 127 | int columnCount = sqlite3_column_count([_statement statement]); 128 | 129 | int columnIdx = 0; 130 | for (columnIdx = 0; columnIdx < columnCount; columnIdx++) { 131 | 132 | NSString *columnName = [NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)]; 133 | id objectValue = [self objectForColumnIndex:columnIdx]; 134 | [dict setObject:objectValue forKey:columnName]; 135 | } 136 | 137 | return dict; 138 | } 139 | else { 140 | NSLog(@"Warning: There seem to be no columns in this set."); 141 | } 142 | 143 | return nil; 144 | } 145 | 146 | 147 | 148 | 149 | - (BOOL)next { 150 | return [self nextWithError:nil]; 151 | } 152 | 153 | - (BOOL)nextWithError:(NSError **)outErr { 154 | 155 | int rc = sqlite3_step([_statement statement]); 156 | 157 | if (SQLITE_BUSY == rc || SQLITE_LOCKED == rc) { 158 | NSLog(@"%s:%d Database busy (%@)", __FUNCTION__, __LINE__, [_parentDB databasePath]); 159 | NSLog(@"Database busy"); 160 | if (outErr) { 161 | *outErr = [_parentDB lastError]; 162 | } 163 | } 164 | else if (SQLITE_DONE == rc || SQLITE_ROW == rc) { 165 | // all is well, let's return. 166 | } 167 | else if (SQLITE_ERROR == rc) { 168 | NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); 169 | if (outErr) { 170 | *outErr = [_parentDB lastError]; 171 | } 172 | } 173 | else if (SQLITE_MISUSE == rc) { 174 | // uh oh. 175 | NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); 176 | if (outErr) { 177 | if (_parentDB) { 178 | *outErr = [_parentDB lastError]; 179 | } 180 | else { 181 | // If 'next' or 'nextWithError' is called after the result set is closed, 182 | // we need to return the appropriate error. 183 | NSDictionary* errorMessage = [NSDictionary dictionaryWithObject:@"parentDB does not exist" forKey:NSLocalizedDescriptionKey]; 184 | *outErr = [NSError errorWithDomain:@"FMDatabase" code:SQLITE_MISUSE userInfo:errorMessage]; 185 | } 186 | 187 | } 188 | } 189 | else { 190 | // wtf? 191 | NSLog(@"Unknown error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); 192 | if (outErr) { 193 | *outErr = [_parentDB lastError]; 194 | } 195 | } 196 | 197 | 198 | if (rc != SQLITE_ROW) { 199 | [self close]; 200 | } 201 | 202 | return (rc == SQLITE_ROW); 203 | } 204 | 205 | - (BOOL)hasAnotherRow { 206 | return sqlite3_errcode([_parentDB sqliteHandle]) == SQLITE_ROW; 207 | } 208 | 209 | - (int)columnIndexForName:(NSString*)columnName { 210 | columnName = [columnName lowercaseString]; 211 | 212 | NSNumber *n = [[self columnNameToIndexMap] objectForKey:columnName]; 213 | 214 | if (n) { 215 | return [n intValue]; 216 | } 217 | 218 | NSLog(@"Warning: I could not find the column named '%@'.", columnName); 219 | 220 | return -1; 221 | } 222 | 223 | 224 | 225 | - (int)intForColumn:(NSString*)columnName { 226 | return [self intForColumnIndex:[self columnIndexForName:columnName]]; 227 | } 228 | 229 | - (int)intForColumnIndex:(int)columnIdx { 230 | return sqlite3_column_int([_statement statement], columnIdx); 231 | } 232 | 233 | - (long)longForColumn:(NSString*)columnName { 234 | return [self longForColumnIndex:[self columnIndexForName:columnName]]; 235 | } 236 | 237 | - (long)longForColumnIndex:(int)columnIdx { 238 | return (long)sqlite3_column_int64([_statement statement], columnIdx); 239 | } 240 | 241 | - (long long int)longLongIntForColumn:(NSString*)columnName { 242 | return [self longLongIntForColumnIndex:[self columnIndexForName:columnName]]; 243 | } 244 | 245 | - (long long int)longLongIntForColumnIndex:(int)columnIdx { 246 | return sqlite3_column_int64([_statement statement], columnIdx); 247 | } 248 | 249 | - (unsigned long long int)unsignedLongLongIntForColumn:(NSString*)columnName { 250 | return [self unsignedLongLongIntForColumnIndex:[self columnIndexForName:columnName]]; 251 | } 252 | 253 | - (unsigned long long int)unsignedLongLongIntForColumnIndex:(int)columnIdx { 254 | return (unsigned long long int)[self longLongIntForColumnIndex:columnIdx]; 255 | } 256 | 257 | - (BOOL)boolForColumn:(NSString*)columnName { 258 | return [self boolForColumnIndex:[self columnIndexForName:columnName]]; 259 | } 260 | 261 | - (BOOL)boolForColumnIndex:(int)columnIdx { 262 | return ([self intForColumnIndex:columnIdx] != 0); 263 | } 264 | 265 | - (double)doubleForColumn:(NSString*)columnName { 266 | return [self doubleForColumnIndex:[self columnIndexForName:columnName]]; 267 | } 268 | 269 | - (double)doubleForColumnIndex:(int)columnIdx { 270 | return sqlite3_column_double([_statement statement], columnIdx); 271 | } 272 | 273 | - (NSString*)stringForColumnIndex:(int)columnIdx { 274 | 275 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { 276 | return nil; 277 | } 278 | 279 | const char *c = (const char *)sqlite3_column_text([_statement statement], columnIdx); 280 | 281 | if (!c) { 282 | // null row. 283 | return nil; 284 | } 285 | 286 | return [NSString stringWithUTF8String:c]; 287 | } 288 | 289 | - (NSString*)stringForColumn:(NSString*)columnName { 290 | return [self stringForColumnIndex:[self columnIndexForName:columnName]]; 291 | } 292 | 293 | - (NSDate*)dateForColumn:(NSString*)columnName { 294 | return [self dateForColumnIndex:[self columnIndexForName:columnName]]; 295 | } 296 | 297 | - (NSDate*)dateForColumnIndex:(int)columnIdx { 298 | 299 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { 300 | return nil; 301 | } 302 | 303 | return [_parentDB hasDateFormatter] ? [_parentDB dateFromString:[self stringForColumnIndex:columnIdx]] : [NSDate dateWithTimeIntervalSince1970:[self doubleForColumnIndex:columnIdx]]; 304 | } 305 | 306 | 307 | - (NSData*)dataForColumn:(NSString*)columnName { 308 | return [self dataForColumnIndex:[self columnIndexForName:columnName]]; 309 | } 310 | 311 | - (NSData*)dataForColumnIndex:(int)columnIdx { 312 | 313 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { 314 | return nil; 315 | } 316 | 317 | const char *dataBuffer = sqlite3_column_blob([_statement statement], columnIdx); 318 | int dataSize = sqlite3_column_bytes([_statement statement], columnIdx); 319 | 320 | if (dataBuffer == NULL) { 321 | return nil; 322 | } 323 | 324 | return [NSData dataWithBytes:(const void *)dataBuffer length:(NSUInteger)dataSize]; 325 | } 326 | 327 | 328 | - (NSData*)dataNoCopyForColumn:(NSString*)columnName { 329 | return [self dataNoCopyForColumnIndex:[self columnIndexForName:columnName]]; 330 | } 331 | 332 | - (NSData*)dataNoCopyForColumnIndex:(int)columnIdx { 333 | 334 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { 335 | return nil; 336 | } 337 | 338 | const char *dataBuffer = sqlite3_column_blob([_statement statement], columnIdx); 339 | int dataSize = sqlite3_column_bytes([_statement statement], columnIdx); 340 | 341 | NSData *data = [NSData dataWithBytesNoCopy:(void *)dataBuffer length:(NSUInteger)dataSize freeWhenDone:NO]; 342 | 343 | return data; 344 | } 345 | 346 | 347 | - (BOOL)columnIndexIsNull:(int)columnIdx { 348 | return sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL; 349 | } 350 | 351 | - (BOOL)columnIsNull:(NSString*)columnName { 352 | return [self columnIndexIsNull:[self columnIndexForName:columnName]]; 353 | } 354 | 355 | - (const unsigned char *)UTF8StringForColumnIndex:(int)columnIdx { 356 | 357 | if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { 358 | return nil; 359 | } 360 | 361 | return sqlite3_column_text([_statement statement], columnIdx); 362 | } 363 | 364 | - (const unsigned char *)UTF8StringForColumnName:(NSString*)columnName { 365 | return [self UTF8StringForColumnIndex:[self columnIndexForName:columnName]]; 366 | } 367 | 368 | - (id)objectForColumnIndex:(int)columnIdx { 369 | int columnType = sqlite3_column_type([_statement statement], columnIdx); 370 | 371 | id returnValue = nil; 372 | 373 | if (columnType == SQLITE_INTEGER) { 374 | returnValue = [NSNumber numberWithLongLong:[self longLongIntForColumnIndex:columnIdx]]; 375 | } 376 | else if (columnType == SQLITE_FLOAT) { 377 | returnValue = [NSNumber numberWithDouble:[self doubleForColumnIndex:columnIdx]]; 378 | } 379 | else if (columnType == SQLITE_BLOB) { 380 | returnValue = [self dataForColumnIndex:columnIdx]; 381 | } 382 | else { 383 | //default to a string for everything else 384 | returnValue = [self stringForColumnIndex:columnIdx]; 385 | } 386 | 387 | if (returnValue == nil) { 388 | returnValue = [NSNull null]; 389 | } 390 | 391 | return returnValue; 392 | } 393 | 394 | - (id)objectForColumnName:(NSString*)columnName { 395 | return [self objectForColumnIndex:[self columnIndexForName:columnName]]; 396 | } 397 | 398 | // returns autoreleased NSString containing the name of the column in the result set 399 | - (NSString*)columnNameForIndex:(int)columnIdx { 400 | return [NSString stringWithUTF8String: sqlite3_column_name([_statement statement], columnIdx)]; 401 | } 402 | 403 | - (void)setParentDB:(FMDatabase *)newDb { 404 | _parentDB = newDb; 405 | } 406 | 407 | - (id)objectAtIndexedSubscript:(int)columnIdx { 408 | return [self objectForColumnIndex:columnIdx]; 409 | } 410 | 411 | - (id)objectForKeyedSubscript:(NSString *)columnName { 412 | return [self objectForColumnName:columnName]; 413 | } 414 | 415 | 416 | @end 417 | -------------------------------------------------------------------------------- /TextUtil/OpenSources/FMDB/FMResultSet.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "sqlite3.h" 3 | 4 | #ifndef __has_feature // Optional. 5 | #define __has_feature(x) 0 // Compatibility with non-clang compilers. 6 | #endif 7 | 8 | #ifndef NS_RETURNS_NOT_RETAINED 9 | #if __has_feature(attribute_ns_returns_not_retained) 10 | #define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained)) 11 | #else 12 | #define NS_RETURNS_NOT_RETAINED 13 | #endif 14 | #endif 15 | 16 | @class FMDatabase; 17 | @class FMStatement; 18 | 19 | /** Represents the results of executing a query on an ``. 20 | 21 | ### See also 22 | 23 | - `` 24 | */ 25 | 26 | @interface FMResultSet : NSObject { 27 | FMDatabase *_parentDB; 28 | FMStatement *_statement; 29 | 30 | NSString *_query; 31 | NSMutableDictionary *_columnNameToIndexMap; 32 | } 33 | 34 | ///----------------- 35 | /// @name Properties 36 | ///----------------- 37 | 38 | /** Executed query */ 39 | 40 | @property (atomic, retain) NSString *query; 41 | 42 | /** `NSMutableDictionary` mapping column names to numeric index */ 43 | 44 | @property (readonly) NSMutableDictionary *columnNameToIndexMap; 45 | 46 | /** `FMStatement` used by result set. */ 47 | 48 | @property (atomic, retain) FMStatement *statement; 49 | 50 | ///------------------------------------ 51 | /// @name Creating and closing database 52 | ///------------------------------------ 53 | 54 | /** Create result set from `` 55 | 56 | @param statement A `` to be performed 57 | 58 | @param aDB A `` to be used 59 | 60 | @return A `FMResultSet` on success; `nil` on failure 61 | */ 62 | 63 | + (instancetype)resultSetWithStatement:(FMStatement *)statement usingParentDatabase:(FMDatabase*)aDB; 64 | 65 | /** Close result set */ 66 | 67 | - (void)close; 68 | 69 | - (void)setParentDB:(FMDatabase *)newDb; 70 | 71 | ///--------------------------------------- 72 | /// @name Iterating through the result set 73 | ///--------------------------------------- 74 | 75 | /** Retrieve next row for result set. 76 | 77 | You must always invoke `next` or `nextWithError` before attempting to access the values returned in a query, even if you're only expecting one. 78 | 79 | @return `YES` if row successfully retrieved; `NO` if end of result set reached 80 | 81 | @see hasAnotherRow 82 | */ 83 | 84 | - (BOOL)next; 85 | 86 | /** Retrieve next row for result set. 87 | 88 | You must always invoke `next` or `nextWithError` before attempting to access the values returned in a query, even if you're only expecting one. 89 | 90 | @param outErr A 'NSError' object to receive any error object (if any). 91 | 92 | @return 'YES' if row successfully retrieved; 'NO' if end of result set reached 93 | 94 | @see hasAnotherRow 95 | */ 96 | 97 | - (BOOL)nextWithError:(NSError **)outErr; 98 | 99 | /** Did the last call to `` succeed in retrieving another row? 100 | 101 | @return `YES` if the last call to `` succeeded in retrieving another record; `NO` if not. 102 | 103 | @see next 104 | 105 | @warning The `hasAnotherRow` method must follow a call to ``. If the previous database interaction was something other than a call to `next`, then this method may return `NO`, whether there is another row of data or not. 106 | */ 107 | 108 | - (BOOL)hasAnotherRow; 109 | 110 | ///--------------------------------------------- 111 | /// @name Retrieving information from result set 112 | ///--------------------------------------------- 113 | 114 | /** How many columns in result set 115 | 116 | @return Integer value of the number of columns. 117 | */ 118 | 119 | - (int)columnCount; 120 | 121 | /** Column index for column name 122 | 123 | @param columnName `NSString` value of the name of the column. 124 | 125 | @return Zero-based index for column. 126 | */ 127 | 128 | - (int)columnIndexForName:(NSString*)columnName; 129 | 130 | /** Column name for column index 131 | 132 | @param columnIdx Zero-based index for column. 133 | 134 | @return columnName `NSString` value of the name of the column. 135 | */ 136 | 137 | - (NSString*)columnNameForIndex:(int)columnIdx; 138 | 139 | /** Result set integer value for column. 140 | 141 | @param columnName `NSString` value of the name of the column. 142 | 143 | @return `int` value of the result set's column. 144 | */ 145 | 146 | - (int)intForColumn:(NSString*)columnName; 147 | 148 | /** Result set integer value for column. 149 | 150 | @param columnIdx Zero-based index for column. 151 | 152 | @return `int` value of the result set's column. 153 | */ 154 | 155 | - (int)intForColumnIndex:(int)columnIdx; 156 | 157 | /** Result set `long` value for column. 158 | 159 | @param columnName `NSString` value of the name of the column. 160 | 161 | @return `long` value of the result set's column. 162 | */ 163 | 164 | - (long)longForColumn:(NSString*)columnName; 165 | 166 | /** Result set long value for column. 167 | 168 | @param columnIdx Zero-based index for column. 169 | 170 | @return `long` value of the result set's column. 171 | */ 172 | 173 | - (long)longForColumnIndex:(int)columnIdx; 174 | 175 | /** Result set `long long int` value for column. 176 | 177 | @param columnName `NSString` value of the name of the column. 178 | 179 | @return `long long int` value of the result set's column. 180 | */ 181 | 182 | - (long long int)longLongIntForColumn:(NSString*)columnName; 183 | 184 | /** Result set `long long int` value for column. 185 | 186 | @param columnIdx Zero-based index for column. 187 | 188 | @return `long long int` value of the result set's column. 189 | */ 190 | 191 | - (long long int)longLongIntForColumnIndex:(int)columnIdx; 192 | 193 | /** Result set `unsigned long long int` value for column. 194 | 195 | @param columnName `NSString` value of the name of the column. 196 | 197 | @return `unsigned long long int` value of the result set's column. 198 | */ 199 | 200 | - (unsigned long long int)unsignedLongLongIntForColumn:(NSString*)columnName; 201 | 202 | /** Result set `unsigned long long int` value for column. 203 | 204 | @param columnIdx Zero-based index for column. 205 | 206 | @return `unsigned long long int` value of the result set's column. 207 | */ 208 | 209 | - (unsigned long long int)unsignedLongLongIntForColumnIndex:(int)columnIdx; 210 | 211 | /** Result set `BOOL` value for column. 212 | 213 | @param columnName `NSString` value of the name of the column. 214 | 215 | @return `BOOL` value of the result set's column. 216 | */ 217 | 218 | - (BOOL)boolForColumn:(NSString*)columnName; 219 | 220 | /** Result set `BOOL` value for column. 221 | 222 | @param columnIdx Zero-based index for column. 223 | 224 | @return `BOOL` value of the result set's column. 225 | */ 226 | 227 | - (BOOL)boolForColumnIndex:(int)columnIdx; 228 | 229 | /** Result set `double` value for column. 230 | 231 | @param columnName `NSString` value of the name of the column. 232 | 233 | @return `double` value of the result set's column. 234 | 235 | */ 236 | 237 | - (double)doubleForColumn:(NSString*)columnName; 238 | 239 | /** Result set `double` value for column. 240 | 241 | @param columnIdx Zero-based index for column. 242 | 243 | @return `double` value of the result set's column. 244 | 245 | */ 246 | 247 | - (double)doubleForColumnIndex:(int)columnIdx; 248 | 249 | /** Result set `NSString` value for column. 250 | 251 | @param columnName `NSString` value of the name of the column. 252 | 253 | @return `NSString` value of the result set's column. 254 | 255 | */ 256 | 257 | - (NSString*)stringForColumn:(NSString*)columnName; 258 | 259 | /** Result set `NSString` value for column. 260 | 261 | @param columnIdx Zero-based index for column. 262 | 263 | @return `NSString` value of the result set's column. 264 | */ 265 | 266 | - (NSString*)stringForColumnIndex:(int)columnIdx; 267 | 268 | /** Result set `NSDate` value for column. 269 | 270 | @param columnName `NSString` value of the name of the column. 271 | 272 | @return `NSDate` value of the result set's column. 273 | */ 274 | 275 | - (NSDate*)dateForColumn:(NSString*)columnName; 276 | 277 | /** Result set `NSDate` value for column. 278 | 279 | @param columnIdx Zero-based index for column. 280 | 281 | @return `NSDate` value of the result set's column. 282 | 283 | */ 284 | 285 | - (NSDate*)dateForColumnIndex:(int)columnIdx; 286 | 287 | /** Result set `NSData` value for column. 288 | 289 | This is useful when storing binary data in table (such as image or the like). 290 | 291 | @param columnName `NSString` value of the name of the column. 292 | 293 | @return `NSData` value of the result set's column. 294 | 295 | */ 296 | 297 | - (NSData*)dataForColumn:(NSString*)columnName; 298 | 299 | /** Result set `NSData` value for column. 300 | 301 | @param columnIdx Zero-based index for column. 302 | 303 | @return `NSData` value of the result set's column. 304 | */ 305 | 306 | - (NSData*)dataForColumnIndex:(int)columnIdx; 307 | 308 | /** Result set `(const unsigned char *)` value for column. 309 | 310 | @param columnName `NSString` value of the name of the column. 311 | 312 | @return `(const unsigned char *)` value of the result set's column. 313 | */ 314 | 315 | - (const unsigned char *)UTF8StringForColumnName:(NSString*)columnName; 316 | 317 | /** Result set `(const unsigned char *)` value for column. 318 | 319 | @param columnIdx Zero-based index for column. 320 | 321 | @return `(const unsigned char *)` value of the result set's column. 322 | */ 323 | 324 | - (const unsigned char *)UTF8StringForColumnIndex:(int)columnIdx; 325 | 326 | /** Result set object for column. 327 | 328 | @param columnName `NSString` value of the name of the column. 329 | 330 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. 331 | 332 | @see objectForKeyedSubscript: 333 | */ 334 | 335 | - (id)objectForColumnName:(NSString*)columnName; 336 | 337 | /** Result set object for column. 338 | 339 | @param columnIdx Zero-based index for column. 340 | 341 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. 342 | 343 | @see objectAtIndexedSubscript: 344 | */ 345 | 346 | - (id)objectForColumnIndex:(int)columnIdx; 347 | 348 | /** Result set object for column. 349 | 350 | This method allows the use of the "boxed" syntax supported in Modern Objective-C. For example, by defining this method, the following syntax is now supported: 351 | 352 | id result = rs[@"employee_name"]; 353 | 354 | This simplified syntax is equivalent to calling: 355 | 356 | id result = [rs objectForKeyedSubscript:@"employee_name"]; 357 | 358 | which is, it turns out, equivalent to calling: 359 | 360 | id result = [rs objectForColumnName:@"employee_name"]; 361 | 362 | @param columnName `NSString` value of the name of the column. 363 | 364 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. 365 | */ 366 | 367 | - (id)objectForKeyedSubscript:(NSString *)columnName; 368 | 369 | /** Result set object for column. 370 | 371 | This method allows the use of the "boxed" syntax supported in Modern Objective-C. For example, by defining this method, the following syntax is now supported: 372 | 373 | id result = rs[0]; 374 | 375 | This simplified syntax is equivalent to calling: 376 | 377 | id result = [rs objectForKeyedSubscript:0]; 378 | 379 | which is, it turns out, equivalent to calling: 380 | 381 | id result = [rs objectForColumnName:0]; 382 | 383 | @param columnIdx Zero-based index for column. 384 | 385 | @return Either `NSNumber`, `NSString`, `NSData`, or `NSNull`. If the column was `NULL`, this returns `[NSNull null]` object. 386 | */ 387 | 388 | - (id)objectAtIndexedSubscript:(int)columnIdx; 389 | 390 | /** Result set `NSData` value for column. 391 | 392 | @param columnName `NSString` value of the name of the column. 393 | 394 | @return `NSData` value of the result set's column. 395 | 396 | @warning If you are going to use this data after you iterate over the next row, or after you close the 397 | result set, make sure to make a copy of the data first (or just use ``/``) 398 | If you don't, you're going to be in a world of hurt when you try and use the data. 399 | 400 | */ 401 | 402 | - (NSData*)dataNoCopyForColumn:(NSString*)columnName NS_RETURNS_NOT_RETAINED; 403 | 404 | /** Result set `NSData` value for column. 405 | 406 | @param columnIdx Zero-based index for column. 407 | 408 | @return `NSData` value of the result set's column. 409 | 410 | @warning If you are going to use this data after you iterate over the next row, or after you close the 411 | result set, make sure to make a copy of the data first (or just use ``/``) 412 | If you don't, you're going to be in a world of hurt when you try and use the data. 413 | 414 | */ 415 | 416 | - (NSData*)dataNoCopyForColumnIndex:(int)columnIdx NS_RETURNS_NOT_RETAINED; 417 | 418 | /** Is the column `NULL`? 419 | 420 | @param columnIdx Zero-based index for column. 421 | 422 | @return `YES` if column is `NULL`; `NO` if not `NULL`. 423 | */ 424 | 425 | - (BOOL)columnIndexIsNull:(int)columnIdx; 426 | 427 | /** Is the column `NULL`? 428 | 429 | @param columnName `NSString` value of the name of the column. 430 | 431 | @return `YES` if column is `NULL`; `NO` if not `NULL`. 432 | */ 433 | 434 | - (BOOL)columnIsNull:(NSString*)columnName; 435 | 436 | 437 | /** Returns a dictionary of the row results mapped to case sensitive keys of the column names. 438 | 439 | @returns `NSDictionary` of the row results. 440 | 441 | @warning The keys to the dictionary are case sensitive of the column names. 442 | */ 443 | 444 | - (NSDictionary*)resultDictionary; 445 | 446 | /** Returns a dictionary of the row results 447 | 448 | @see resultDictionary 449 | 450 | @warning **Deprecated**: Please use `` instead. Also, beware that `` is case sensitive! 451 | */ 452 | 453 | - (NSDictionary*)resultDict __attribute__ ((deprecated)); 454 | 455 | ///----------------------------- 456 | /// @name Key value coding magic 457 | ///----------------------------- 458 | 459 | /** Performs `setValue` to yield support for key value observing. 460 | 461 | @param object The object for which the values will be set. This is the key-value-coding compliant object that you might, for example, observe. 462 | 463 | */ 464 | 465 | - (void)kvcMagic:(id)object; 466 | 467 | 468 | @end 469 | 470 | --------------------------------------------------------------------------------