├── .gitignore ├── .travis.yml ├── Example ├── Podfile ├── Podfile.lock ├── Pods │ ├── Local Podspecs │ │ └── RJBadgeKit.podspec.json │ ├── Manifest.lock │ ├── Pods.xcodeproj │ │ └── project.pbxproj │ └── Target Support Files │ │ ├── Pods-RJBadgeKit_Example │ │ ├── Info.plist │ │ ├── Pods-RJBadgeKit_Example-acknowledgements.markdown │ │ ├── Pods-RJBadgeKit_Example-acknowledgements.plist │ │ ├── Pods-RJBadgeKit_Example-dummy.m │ │ ├── Pods-RJBadgeKit_Example-frameworks.sh │ │ ├── Pods-RJBadgeKit_Example-resources.sh │ │ ├── Pods-RJBadgeKit_Example-umbrella.h │ │ ├── Pods-RJBadgeKit_Example.debug.xcconfig │ │ ├── Pods-RJBadgeKit_Example.modulemap │ │ └── Pods-RJBadgeKit_Example.release.xcconfig │ │ ├── Pods-RJBadgeKit_Tests │ │ ├── Info.plist │ │ ├── Pods-RJBadgeKit_Tests-acknowledgements.markdown │ │ ├── Pods-RJBadgeKit_Tests-acknowledgements.plist │ │ ├── Pods-RJBadgeKit_Tests-dummy.m │ │ ├── Pods-RJBadgeKit_Tests-frameworks.sh │ │ ├── Pods-RJBadgeKit_Tests-resources.sh │ │ ├── Pods-RJBadgeKit_Tests-umbrella.h │ │ ├── Pods-RJBadgeKit_Tests.debug.xcconfig │ │ ├── Pods-RJBadgeKit_Tests.modulemap │ │ └── Pods-RJBadgeKit_Tests.release.xcconfig │ │ └── RJBadgeKit │ │ ├── Info.plist │ │ ├── RJBadgeKit-dummy.m │ │ ├── RJBadgeKit-prefix.pch │ │ ├── RJBadgeKit-umbrella.h │ │ ├── RJBadgeKit.modulemap │ │ └── RJBadgeKit.xcconfig ├── RJBadgeKit.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── RJBadgeKit-Example.xcscheme ├── RJBadgeKit.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── RJBadgeKit │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Contents.json │ │ └── badgeNew.imageset │ │ │ ├── Contents.json │ │ │ ├── badgeNew@2x.png │ │ │ └── badgeNew@3x.png │ ├── RJAppDelegate.h │ ├── RJAppDelegate.m │ ├── RJBadgeKit-Info.plist │ ├── RJBadgeKit-Prefix.pch │ ├── RJDemoViewController.h │ ├── RJDemoViewController.m │ ├── RJDetailViewController.h │ ├── RJDetailViewController.m │ ├── RJViewController.h │ ├── RJViewController.m │ ├── en.lproj │ │ └── InfoPlist.strings │ └── main.m ├── Tests │ ├── Tests-Info.plist │ ├── Tests-Prefix.pch │ ├── Tests.m │ └── en.lproj │ │ └── InfoPlist.strings ├── demo.gif └── path.png ├── LICENSE ├── README.md ├── RJBadgeKit.podspec ├── RJBadgeKit ├── Assets │ └── .gitkeep └── Classes │ ├── .gitkeep │ ├── BadgeController │ ├── NSObject+RJBadgeController.h │ ├── NSObject+RJBadgeController.m │ ├── RJBadgeController.h │ ├── RJBadgeController.m │ ├── RJBadgeManager.h │ └── RJBadgeManager.m │ ├── BadgeModel │ ├── RJBadge.h │ ├── RJBadgeInfo.h │ ├── RJBadgeInfo.m │ ├── RJBadgeModel.h │ └── RJBadgeModel.m │ ├── BadgeView │ ├── RJBadgeView.h │ ├── UIBarButtonItem+RJBadge.h │ ├── UIBarButtonItem+RJBadge.m │ ├── UITabBarItem+RJBadge.h │ ├── UITabBarItem+RJBadge.m │ ├── UIView+RJBadge.h │ └── UIView+RJBadge.m │ ├── Helper │ ├── NSString+RJBadge.h │ └── NSString+RJBadge.m │ └── RJBadgeKit.h └── _Pods.xcodeproj /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | build/ 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | xcuserdata/ 15 | *.xccheckout 16 | profile 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | 22 | # Bundler 23 | .bundle 24 | 25 | Carthage 26 | # We recommend against adding the Pods directory to your .gitignore. However 27 | # you should judge for yourself, the pros and cons are mentioned at: 28 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 29 | # 30 | # Note: if you ignore the Pods directory, make sure to uncomment 31 | # `pod install` in .travis.yml 32 | # 33 | # Pods/ 34 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # references: 2 | # * http://www.objc.io/issue-6/travis-ci.html 3 | # * https://github.com/supermarin/xcpretty#usage 4 | 5 | osx_image: xcode7.3 6 | language: objective-c 7 | # cache: cocoapods 8 | # podfile: Example/Podfile 9 | # before_install: 10 | # - gem install cocoapods # Since Travis is not always on latest version 11 | # - pod install --project-directory=Example 12 | script: 13 | - set -o pipefail && xcodebuild test -enableCodeCoverage YES -workspace Example/RJBadgeKit.xcworkspace -scheme RJBadgeKit-Example -sdk iphonesimulator9.3 ONLY_ACTIVE_ARCH=NO | xcpretty 14 | - pod lib lint 15 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | target 'RJBadgeKit_Example' do 4 | pod 'RJBadgeKit', :path => '../' 5 | 6 | target 'RJBadgeKit_Tests' do 7 | inherit! :search_paths 8 | 9 | 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /Example/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - RJBadgeKit (0.2.1) 3 | 4 | DEPENDENCIES: 5 | - RJBadgeKit (from `../`) 6 | 7 | EXTERNAL SOURCES: 8 | RJBadgeKit: 9 | :path: ../ 10 | 11 | SPEC CHECKSUMS: 12 | RJBadgeKit: db6f8f09f92f92e2473142aa4fee46121de6d716 13 | 14 | PODFILE CHECKSUM: 2fb6b623b87aeb174cd13a4c34101b548b391a79 15 | 16 | COCOAPODS: 1.3.1 17 | -------------------------------------------------------------------------------- /Example/Pods/Local Podspecs/RJBadgeKit.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "RJBadgeKit", 3 | "version": "0.2.1", 4 | "summary": "Red dot (version/message reminder) display and its management.", 5 | "description": "A complete and lightweight solution for red dot (version/message reminder) display and its management.", 6 | "homepage": "https://github.com/RylanJIN/RJBadgeKit", 7 | "license": { 8 | "type": "MIT", 9 | "file": "LICENSE" 10 | }, 11 | "authors": { 12 | "Ryan Jin": "xiaojun.jin@outlook.com" 13 | }, 14 | "source": { 15 | "git": "https://github.com/RylanJIN/RJBadgeKit.git", 16 | "tag": "0.2.1" 17 | }, 18 | "platforms": { 19 | "ios": "8.0" 20 | }, 21 | "source_files": "RJBadgeKit/Classes/**/*" 22 | } 23 | -------------------------------------------------------------------------------- /Example/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - RJBadgeKit (0.2.1) 3 | 4 | DEPENDENCIES: 5 | - RJBadgeKit (from `../`) 6 | 7 | EXTERNAL SOURCES: 8 | RJBadgeKit: 9 | :path: ../ 10 | 11 | SPEC CHECKSUMS: 12 | RJBadgeKit: db6f8f09f92f92e2473142aa4fee46121de6d716 13 | 14 | PODFILE CHECKSUM: 2fb6b623b87aeb174cd13a4c34101b548b391a79 15 | 16 | COCOAPODS: 1.3.1 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-RJBadgeKit_Example/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-RJBadgeKit_Example/Pods-RJBadgeKit_Example-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## RJBadgeKit 5 | 6 | Copyright (c) 2017 RylanJIN 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | Generated by CocoaPods - https://cocoapods.org 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-RJBadgeKit_Example/Pods-RJBadgeKit_Example-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Copyright (c) 2017 RylanJIN <xiaojun.jin@outlook.com> 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy 20 | of this software and associated documentation files (the "Software"), to deal 21 | in the Software without restriction, including without limitation the rights 22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 | copies of the Software, and to permit persons to whom the Software is 24 | furnished to do so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in 27 | all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 35 | THE SOFTWARE. 36 | 37 | License 38 | MIT 39 | Title 40 | RJBadgeKit 41 | Type 42 | PSGroupSpecifier 43 | 44 | 45 | FooterText 46 | Generated by CocoaPods - https://cocoapods.org 47 | Title 48 | 49 | Type 50 | PSGroupSpecifier 51 | 52 | 53 | StringsTable 54 | Acknowledgements 55 | Title 56 | Acknowledgements 57 | 58 | 59 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-RJBadgeKit_Example/Pods-RJBadgeKit_Example-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_RJBadgeKit_Example : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_RJBadgeKit_Example 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-RJBadgeKit_Example/Pods-RJBadgeKit_Example-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 6 | 7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 8 | 9 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 10 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 11 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 12 | 13 | install_framework() 14 | { 15 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 16 | local source="${BUILT_PRODUCTS_DIR}/$1" 17 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 18 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 19 | elif [ -r "$1" ]; then 20 | local source="$1" 21 | fi 22 | 23 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 24 | 25 | if [ -L "${source}" ]; then 26 | echo "Symlinked..." 27 | source="$(readlink "${source}")" 28 | fi 29 | 30 | # Use filter instead of exclude so missing patterns don't throw errors. 31 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 32 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 33 | 34 | local basename 35 | basename="$(basename -s .framework "$1")" 36 | binary="${destination}/${basename}.framework/${basename}" 37 | if ! [ -r "$binary" ]; then 38 | binary="${destination}/${basename}" 39 | fi 40 | 41 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 42 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 43 | strip_invalid_archs "$binary" 44 | fi 45 | 46 | # Resign the code if required by the build settings to avoid unstable apps 47 | code_sign_if_enabled "${destination}/$(basename "$1")" 48 | 49 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 50 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 51 | local swift_runtime_libs 52 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 53 | for lib in $swift_runtime_libs; do 54 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 55 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 56 | code_sign_if_enabled "${destination}/${lib}" 57 | done 58 | fi 59 | } 60 | 61 | # Copies the dSYM of a vendored framework 62 | install_dsym() { 63 | local source="$1" 64 | if [ -r "$source" ]; then 65 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DWARF_DSYM_FOLDER_PATH}\"" 66 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DWARF_DSYM_FOLDER_PATH}" 67 | fi 68 | } 69 | 70 | # Signs a framework with the provided identity 71 | code_sign_if_enabled() { 72 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 73 | # Use the current code_sign_identitiy 74 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 75 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements '$1'" 76 | 77 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 78 | code_sign_cmd="$code_sign_cmd &" 79 | fi 80 | echo "$code_sign_cmd" 81 | eval "$code_sign_cmd" 82 | fi 83 | } 84 | 85 | # Strip invalid architectures 86 | strip_invalid_archs() { 87 | binary="$1" 88 | # Get architectures for current file 89 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" 90 | stripped="" 91 | for arch in $archs; do 92 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 93 | # Strip non-valid architectures in-place 94 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 95 | stripped="$stripped $arch" 96 | fi 97 | done 98 | if [[ "$stripped" ]]; then 99 | echo "Stripped $binary of architectures:$stripped" 100 | fi 101 | } 102 | 103 | 104 | if [[ "$CONFIGURATION" == "Debug" ]]; then 105 | install_framework "${BUILT_PRODUCTS_DIR}/RJBadgeKit/RJBadgeKit.framework" 106 | fi 107 | if [[ "$CONFIGURATION" == "Release" ]]; then 108 | install_framework "${BUILT_PRODUCTS_DIR}/RJBadgeKit/RJBadgeKit.framework" 109 | fi 110 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 111 | wait 112 | fi 113 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-RJBadgeKit_Example/Pods-RJBadgeKit_Example-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 5 | 6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 7 | > "$RESOURCES_TO_COPY" 8 | 9 | XCASSET_FILES=() 10 | 11 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 12 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 13 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 14 | 15 | case "${TARGETED_DEVICE_FAMILY}" in 16 | 1,2) 17 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 18 | ;; 19 | 1) 20 | TARGET_DEVICE_ARGS="--target-device iphone" 21 | ;; 22 | 2) 23 | TARGET_DEVICE_ARGS="--target-device ipad" 24 | ;; 25 | 3) 26 | TARGET_DEVICE_ARGS="--target-device tv" 27 | ;; 28 | 4) 29 | TARGET_DEVICE_ARGS="--target-device watch" 30 | ;; 31 | *) 32 | TARGET_DEVICE_ARGS="--target-device mac" 33 | ;; 34 | esac 35 | 36 | install_resource() 37 | { 38 | if [[ "$1" = /* ]] ; then 39 | RESOURCE_PATH="$1" 40 | else 41 | RESOURCE_PATH="${PODS_ROOT}/$1" 42 | fi 43 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 44 | cat << EOM 45 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 46 | EOM 47 | exit 1 48 | fi 49 | case $RESOURCE_PATH in 50 | *.storyboard) 51 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 52 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 53 | ;; 54 | *.xib) 55 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 56 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 57 | ;; 58 | *.framework) 59 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 60 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 61 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 62 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 63 | ;; 64 | *.xcdatamodel) 65 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true 66 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 67 | ;; 68 | *.xcdatamodeld) 69 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true 70 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 71 | ;; 72 | *.xcmappingmodel) 73 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true 74 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 75 | ;; 76 | *.xcassets) 77 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 78 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 79 | ;; 80 | *) 81 | echo "$RESOURCE_PATH" || true 82 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 83 | ;; 84 | esac 85 | } 86 | 87 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 88 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 89 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 90 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 91 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 92 | fi 93 | rm -f "$RESOURCES_TO_COPY" 94 | 95 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] 96 | then 97 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 98 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 99 | while read line; do 100 | if [[ $line != "${PODS_ROOT}*" ]]; then 101 | XCASSET_FILES+=("$line") 102 | fi 103 | done <<<"$OTHER_XCASSETS" 104 | 105 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 106 | fi 107 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-RJBadgeKit_Example/Pods-RJBadgeKit_Example-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_RJBadgeKit_ExampleVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_RJBadgeKit_ExampleVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-RJBadgeKit_Example/Pods-RJBadgeKit_Example.debug.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/RJBadgeKit" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 4 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/RJBadgeKit/RJBadgeKit.framework/Headers" 5 | OTHER_LDFLAGS = $(inherited) -framework "RJBadgeKit" 6 | PODS_BUILD_DIR = $BUILD_DIR 7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-RJBadgeKit_Example/Pods-RJBadgeKit_Example.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_RJBadgeKit_Example { 2 | umbrella header "Pods-RJBadgeKit_Example-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-RJBadgeKit_Example/Pods-RJBadgeKit_Example.release.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/RJBadgeKit" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 4 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/RJBadgeKit/RJBadgeKit.framework/Headers" 5 | OTHER_LDFLAGS = $(inherited) -framework "RJBadgeKit" 6 | PODS_BUILD_DIR = $BUILD_DIR 7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-RJBadgeKit_Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-RJBadgeKit_Tests/Pods-RJBadgeKit_Tests-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | Generated by CocoaPods - https://cocoapods.org 4 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-RJBadgeKit_Tests/Pods-RJBadgeKit_Tests-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Generated by CocoaPods - https://cocoapods.org 18 | Title 19 | 20 | Type 21 | PSGroupSpecifier 22 | 23 | 24 | StringsTable 25 | Acknowledgements 26 | Title 27 | Acknowledgements 28 | 29 | 30 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-RJBadgeKit_Tests/Pods-RJBadgeKit_Tests-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_RJBadgeKit_Tests : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_RJBadgeKit_Tests 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-RJBadgeKit_Tests/Pods-RJBadgeKit_Tests-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 6 | 7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 8 | 9 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 10 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 11 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 12 | 13 | install_framework() 14 | { 15 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 16 | local source="${BUILT_PRODUCTS_DIR}/$1" 17 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 18 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 19 | elif [ -r "$1" ]; then 20 | local source="$1" 21 | fi 22 | 23 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 24 | 25 | if [ -L "${source}" ]; then 26 | echo "Symlinked..." 27 | source="$(readlink "${source}")" 28 | fi 29 | 30 | # Use filter instead of exclude so missing patterns don't throw errors. 31 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 32 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 33 | 34 | local basename 35 | basename="$(basename -s .framework "$1")" 36 | binary="${destination}/${basename}.framework/${basename}" 37 | if ! [ -r "$binary" ]; then 38 | binary="${destination}/${basename}" 39 | fi 40 | 41 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 42 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 43 | strip_invalid_archs "$binary" 44 | fi 45 | 46 | # Resign the code if required by the build settings to avoid unstable apps 47 | code_sign_if_enabled "${destination}/$(basename "$1")" 48 | 49 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 50 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 51 | local swift_runtime_libs 52 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 53 | for lib in $swift_runtime_libs; do 54 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 55 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 56 | code_sign_if_enabled "${destination}/${lib}" 57 | done 58 | fi 59 | } 60 | 61 | # Copies the dSYM of a vendored framework 62 | install_dsym() { 63 | local source="$1" 64 | if [ -r "$source" ]; then 65 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DWARF_DSYM_FOLDER_PATH}\"" 66 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DWARF_DSYM_FOLDER_PATH}" 67 | fi 68 | } 69 | 70 | # Signs a framework with the provided identity 71 | code_sign_if_enabled() { 72 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 73 | # Use the current code_sign_identitiy 74 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 75 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements '$1'" 76 | 77 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 78 | code_sign_cmd="$code_sign_cmd &" 79 | fi 80 | echo "$code_sign_cmd" 81 | eval "$code_sign_cmd" 82 | fi 83 | } 84 | 85 | # Strip invalid architectures 86 | strip_invalid_archs() { 87 | binary="$1" 88 | # Get architectures for current file 89 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" 90 | stripped="" 91 | for arch in $archs; do 92 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 93 | # Strip non-valid architectures in-place 94 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 95 | stripped="$stripped $arch" 96 | fi 97 | done 98 | if [[ "$stripped" ]]; then 99 | echo "Stripped $binary of architectures:$stripped" 100 | fi 101 | } 102 | 103 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 104 | wait 105 | fi 106 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-RJBadgeKit_Tests/Pods-RJBadgeKit_Tests-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 5 | 6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 7 | > "$RESOURCES_TO_COPY" 8 | 9 | XCASSET_FILES=() 10 | 11 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 12 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 13 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 14 | 15 | case "${TARGETED_DEVICE_FAMILY}" in 16 | 1,2) 17 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 18 | ;; 19 | 1) 20 | TARGET_DEVICE_ARGS="--target-device iphone" 21 | ;; 22 | 2) 23 | TARGET_DEVICE_ARGS="--target-device ipad" 24 | ;; 25 | 3) 26 | TARGET_DEVICE_ARGS="--target-device tv" 27 | ;; 28 | 4) 29 | TARGET_DEVICE_ARGS="--target-device watch" 30 | ;; 31 | *) 32 | TARGET_DEVICE_ARGS="--target-device mac" 33 | ;; 34 | esac 35 | 36 | install_resource() 37 | { 38 | if [[ "$1" = /* ]] ; then 39 | RESOURCE_PATH="$1" 40 | else 41 | RESOURCE_PATH="${PODS_ROOT}/$1" 42 | fi 43 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 44 | cat << EOM 45 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 46 | EOM 47 | exit 1 48 | fi 49 | case $RESOURCE_PATH in 50 | *.storyboard) 51 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 52 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 53 | ;; 54 | *.xib) 55 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 56 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 57 | ;; 58 | *.framework) 59 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 60 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 61 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 62 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 63 | ;; 64 | *.xcdatamodel) 65 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true 66 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 67 | ;; 68 | *.xcdatamodeld) 69 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true 70 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 71 | ;; 72 | *.xcmappingmodel) 73 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true 74 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 75 | ;; 76 | *.xcassets) 77 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 78 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 79 | ;; 80 | *) 81 | echo "$RESOURCE_PATH" || true 82 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 83 | ;; 84 | esac 85 | } 86 | 87 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 88 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 89 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 90 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 91 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 92 | fi 93 | rm -f "$RESOURCES_TO_COPY" 94 | 95 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] 96 | then 97 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 98 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 99 | while read line; do 100 | if [[ $line != "${PODS_ROOT}*" ]]; then 101 | XCASSET_FILES+=("$line") 102 | fi 103 | done <<<"$OTHER_XCASSETS" 104 | 105 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 106 | fi 107 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-RJBadgeKit_Tests/Pods-RJBadgeKit_Tests-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_RJBadgeKit_TestsVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_RJBadgeKit_TestsVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-RJBadgeKit_Tests/Pods-RJBadgeKit_Tests.debug.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/RJBadgeKit" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 4 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/RJBadgeKit/RJBadgeKit.framework/Headers" 5 | PODS_BUILD_DIR = $BUILD_DIR 6 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 8 | PODS_ROOT = ${SRCROOT}/Pods 9 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-RJBadgeKit_Tests/Pods-RJBadgeKit_Tests.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_RJBadgeKit_Tests { 2 | umbrella header "Pods-RJBadgeKit_Tests-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-RJBadgeKit_Tests/Pods-RJBadgeKit_Tests.release.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/RJBadgeKit" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 4 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/RJBadgeKit/RJBadgeKit.framework/Headers" 5 | PODS_BUILD_DIR = $BUILD_DIR 6 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 8 | PODS_ROOT = ${SRCROOT}/Pods 9 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/RJBadgeKit/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 0.2.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/RJBadgeKit/RJBadgeKit-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_RJBadgeKit : NSObject 3 | @end 4 | @implementation PodsDummy_RJBadgeKit 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/RJBadgeKit/RJBadgeKit-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/RJBadgeKit/RJBadgeKit-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #import "NSObject+RJBadgeController.h" 14 | #import "RJBadgeController.h" 15 | #import "RJBadgeManager.h" 16 | #import "RJBadge.h" 17 | #import "RJBadgeInfo.h" 18 | #import "RJBadgeModel.h" 19 | #import "RJBadgeView.h" 20 | #import "UIBarButtonItem+RJBadge.h" 21 | #import "UITabBarItem+RJBadge.h" 22 | #import "UIView+RJBadge.h" 23 | #import "NSString+RJBadge.h" 24 | #import "RJBadgeKit.h" 25 | 26 | FOUNDATION_EXPORT double RJBadgeKitVersionNumber; 27 | FOUNDATION_EXPORT const unsigned char RJBadgeKitVersionString[]; 28 | 29 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/RJBadgeKit/RJBadgeKit.modulemap: -------------------------------------------------------------------------------- 1 | framework module RJBadgeKit { 2 | umbrella header "RJBadgeKit-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/RJBadgeKit/RJBadgeKit.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/RJBadgeKit 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public" 4 | PODS_BUILD_DIR = $BUILD_DIR 5 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 6 | PODS_ROOT = ${SRCROOT} 7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 9 | SKIP_INSTALL = YES 10 | -------------------------------------------------------------------------------- /Example/RJBadgeKit.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0DD0F3191BF43C6EF9F153DD /* Pods_RJBadgeKit_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 637DF2DA6661A379648E30F1 /* Pods_RJBadgeKit_Example.framework */; }; 11 | 6003F58E195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; }; 12 | 6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58F195388D20070C39A /* CoreGraphics.framework */; }; 13 | 6003F592195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; }; 14 | 6003F598195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F596195388D20070C39A /* InfoPlist.strings */; }; 15 | 6003F59A195388D20070C39A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F599195388D20070C39A /* main.m */; }; 16 | 6003F59E195388D20070C39A /* RJAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F59D195388D20070C39A /* RJAppDelegate.m */; }; 17 | 6003F5A7195388D20070C39A /* RJViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F5A6195388D20070C39A /* RJViewController.m */; }; 18 | 6003F5A9195388D20070C39A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5A8195388D20070C39A /* Images.xcassets */; }; 19 | 6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F5AF195388D20070C39A /* XCTest.framework */; }; 20 | 6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; }; 21 | 6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; }; 22 | 6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5B8195388D20070C39A /* InfoPlist.strings */; }; 23 | 6003F5BC195388D20070C39A /* Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F5BB195388D20070C39A /* Tests.m */; }; 24 | 71719F9F1E33DC2100824A3D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */; }; 25 | 873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */; }; 26 | 94DE14D41FECDD4B00A7FCB3 /* RJDemoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 94DE14D31FECDD4B00A7FCB3 /* RJDemoViewController.m */; }; 27 | 94DE14D71FECDD5C00A7FCB3 /* RJDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 94DE14D61FECDD5C00A7FCB3 /* RJDetailViewController.m */; }; 28 | E306F03EF3AB5DBDF40E4F5B /* Pods_RJBadgeKit_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03485BE7FF6C3D929E410387 /* Pods_RJBadgeKit_Tests.framework */; }; 29 | /* End PBXBuildFile section */ 30 | 31 | /* Begin PBXContainerItemProxy section */ 32 | 6003F5B3195388D20070C39A /* PBXContainerItemProxy */ = { 33 | isa = PBXContainerItemProxy; 34 | containerPortal = 6003F582195388D10070C39A /* Project object */; 35 | proxyType = 1; 36 | remoteGlobalIDString = 6003F589195388D20070C39A; 37 | remoteInfo = RJBadgeKit; 38 | }; 39 | /* End PBXContainerItemProxy section */ 40 | 41 | /* Begin PBXFileReference section */ 42 | 03485BE7FF6C3D929E410387 /* Pods_RJBadgeKit_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RJBadgeKit_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 43 | 26DDFFA3B26F1ABE8A296A1F /* Pods-RJBadgeKit_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RJBadgeKit_Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-RJBadgeKit_Tests/Pods-RJBadgeKit_Tests.release.xcconfig"; sourceTree = ""; }; 44 | 6003F58A195388D20070C39A /* RJBadgeKit_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RJBadgeKit_Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 45 | 6003F58D195388D20070C39A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 46 | 6003F58F195388D20070C39A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 47 | 6003F591195388D20070C39A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 48 | 6003F595195388D20070C39A /* RJBadgeKit-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "RJBadgeKit-Info.plist"; sourceTree = ""; }; 49 | 6003F597195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 50 | 6003F599195388D20070C39A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 51 | 6003F59B195388D20070C39A /* RJBadgeKit-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RJBadgeKit-Prefix.pch"; sourceTree = ""; }; 52 | 6003F59C195388D20070C39A /* RJAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RJAppDelegate.h; sourceTree = ""; }; 53 | 6003F59D195388D20070C39A /* RJAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RJAppDelegate.m; sourceTree = ""; }; 54 | 6003F5A5195388D20070C39A /* RJViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RJViewController.h; sourceTree = ""; }; 55 | 6003F5A6195388D20070C39A /* RJViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RJViewController.m; sourceTree = ""; }; 56 | 6003F5A8195388D20070C39A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 57 | 6003F5AE195388D20070C39A /* RJBadgeKit_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RJBadgeKit_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | 6003F5AF195388D20070C39A /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 59 | 6003F5B7195388D20070C39A /* Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Tests-Info.plist"; sourceTree = ""; }; 60 | 6003F5B9195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 61 | 6003F5BB195388D20070C39A /* Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Tests.m; sourceTree = ""; }; 62 | 606FC2411953D9B200FFA9A0 /* Tests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Tests-Prefix.pch"; sourceTree = ""; }; 63 | 637DF2DA6661A379648E30F1 /* Pods_RJBadgeKit_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RJBadgeKit_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 64 | 71719F9E1E33DC2100824A3D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 65 | 756E1D2C28ADE93AB7B9EB7D /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; 66 | 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Main.storyboard; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 67 | 94DE14D21FECDD4B00A7FCB3 /* RJDemoViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RJDemoViewController.h; sourceTree = ""; }; 68 | 94DE14D31FECDD4B00A7FCB3 /* RJDemoViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RJDemoViewController.m; sourceTree = ""; }; 69 | 94DE14D51FECDD5C00A7FCB3 /* RJDetailViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RJDetailViewController.h; sourceTree = ""; }; 70 | 94DE14D61FECDD5C00A7FCB3 /* RJDetailViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RJDetailViewController.m; sourceTree = ""; }; 71 | A0A17E187F67450CBDC335FF /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; 72 | DCA2EF8D8FA5BE88C7574C6E /* Pods-RJBadgeKit_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RJBadgeKit_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-RJBadgeKit_Example/Pods-RJBadgeKit_Example.release.xcconfig"; sourceTree = ""; }; 73 | E0E8882489A2C9C1186A2792 /* RJBadgeKit.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = RJBadgeKit.podspec; path = ../RJBadgeKit.podspec; sourceTree = ""; }; 74 | E6AB50A9B5D6DEF251B477CB /* Pods-RJBadgeKit_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RJBadgeKit_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RJBadgeKit_Example/Pods-RJBadgeKit_Example.debug.xcconfig"; sourceTree = ""; }; 75 | F4A5749C6C7DE87426F053B7 /* Pods-RJBadgeKit_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RJBadgeKit_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RJBadgeKit_Tests/Pods-RJBadgeKit_Tests.debug.xcconfig"; sourceTree = ""; }; 76 | /* End PBXFileReference section */ 77 | 78 | /* Begin PBXFrameworksBuildPhase section */ 79 | 6003F587195388D20070C39A /* Frameworks */ = { 80 | isa = PBXFrameworksBuildPhase; 81 | buildActionMask = 2147483647; 82 | files = ( 83 | 6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */, 84 | 6003F592195388D20070C39A /* UIKit.framework in Frameworks */, 85 | 6003F58E195388D20070C39A /* Foundation.framework in Frameworks */, 86 | 0DD0F3191BF43C6EF9F153DD /* Pods_RJBadgeKit_Example.framework in Frameworks */, 87 | ); 88 | runOnlyForDeploymentPostprocessing = 0; 89 | }; 90 | 6003F5AB195388D20070C39A /* Frameworks */ = { 91 | isa = PBXFrameworksBuildPhase; 92 | buildActionMask = 2147483647; 93 | files = ( 94 | 6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */, 95 | 6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */, 96 | 6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */, 97 | E306F03EF3AB5DBDF40E4F5B /* Pods_RJBadgeKit_Tests.framework in Frameworks */, 98 | ); 99 | runOnlyForDeploymentPostprocessing = 0; 100 | }; 101 | /* End PBXFrameworksBuildPhase section */ 102 | 103 | /* Begin PBXGroup section */ 104 | 6003F581195388D10070C39A = { 105 | isa = PBXGroup; 106 | children = ( 107 | 60FF7A9C1954A5C5007DD14C /* Podspec Metadata */, 108 | 6003F593195388D20070C39A /* Example for RJBadgeKit */, 109 | 6003F5B5195388D20070C39A /* Tests */, 110 | 6003F58C195388D20070C39A /* Frameworks */, 111 | 6003F58B195388D20070C39A /* Products */, 112 | 63C28FB217854BFA6EBC3042 /* Pods */, 113 | ); 114 | sourceTree = ""; 115 | }; 116 | 6003F58B195388D20070C39A /* Products */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | 6003F58A195388D20070C39A /* RJBadgeKit_Example.app */, 120 | 6003F5AE195388D20070C39A /* RJBadgeKit_Tests.xctest */, 121 | ); 122 | name = Products; 123 | sourceTree = ""; 124 | }; 125 | 6003F58C195388D20070C39A /* Frameworks */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | 6003F58D195388D20070C39A /* Foundation.framework */, 129 | 6003F58F195388D20070C39A /* CoreGraphics.framework */, 130 | 6003F591195388D20070C39A /* UIKit.framework */, 131 | 6003F5AF195388D20070C39A /* XCTest.framework */, 132 | 637DF2DA6661A379648E30F1 /* Pods_RJBadgeKit_Example.framework */, 133 | 03485BE7FF6C3D929E410387 /* Pods_RJBadgeKit_Tests.framework */, 134 | ); 135 | name = Frameworks; 136 | sourceTree = ""; 137 | }; 138 | 6003F593195388D20070C39A /* Example for RJBadgeKit */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | 6003F59C195388D20070C39A /* RJAppDelegate.h */, 142 | 6003F59D195388D20070C39A /* RJAppDelegate.m */, 143 | 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */, 144 | 6003F5A5195388D20070C39A /* RJViewController.h */, 145 | 6003F5A6195388D20070C39A /* RJViewController.m */, 146 | 94DE14D21FECDD4B00A7FCB3 /* RJDemoViewController.h */, 147 | 94DE14D31FECDD4B00A7FCB3 /* RJDemoViewController.m */, 148 | 94DE14D51FECDD5C00A7FCB3 /* RJDetailViewController.h */, 149 | 94DE14D61FECDD5C00A7FCB3 /* RJDetailViewController.m */, 150 | 71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */, 151 | 6003F5A8195388D20070C39A /* Images.xcassets */, 152 | 6003F594195388D20070C39A /* Supporting Files */, 153 | ); 154 | name = "Example for RJBadgeKit"; 155 | path = RJBadgeKit; 156 | sourceTree = ""; 157 | }; 158 | 6003F594195388D20070C39A /* Supporting Files */ = { 159 | isa = PBXGroup; 160 | children = ( 161 | 6003F595195388D20070C39A /* RJBadgeKit-Info.plist */, 162 | 6003F596195388D20070C39A /* InfoPlist.strings */, 163 | 6003F599195388D20070C39A /* main.m */, 164 | 6003F59B195388D20070C39A /* RJBadgeKit-Prefix.pch */, 165 | ); 166 | name = "Supporting Files"; 167 | sourceTree = ""; 168 | }; 169 | 6003F5B5195388D20070C39A /* Tests */ = { 170 | isa = PBXGroup; 171 | children = ( 172 | 6003F5BB195388D20070C39A /* Tests.m */, 173 | 6003F5B6195388D20070C39A /* Supporting Files */, 174 | ); 175 | path = Tests; 176 | sourceTree = ""; 177 | }; 178 | 6003F5B6195388D20070C39A /* Supporting Files */ = { 179 | isa = PBXGroup; 180 | children = ( 181 | 6003F5B7195388D20070C39A /* Tests-Info.plist */, 182 | 6003F5B8195388D20070C39A /* InfoPlist.strings */, 183 | 606FC2411953D9B200FFA9A0 /* Tests-Prefix.pch */, 184 | ); 185 | name = "Supporting Files"; 186 | sourceTree = ""; 187 | }; 188 | 60FF7A9C1954A5C5007DD14C /* Podspec Metadata */ = { 189 | isa = PBXGroup; 190 | children = ( 191 | E0E8882489A2C9C1186A2792 /* RJBadgeKit.podspec */, 192 | A0A17E187F67450CBDC335FF /* README.md */, 193 | 756E1D2C28ADE93AB7B9EB7D /* LICENSE */, 194 | ); 195 | name = "Podspec Metadata"; 196 | sourceTree = ""; 197 | }; 198 | 63C28FB217854BFA6EBC3042 /* Pods */ = { 199 | isa = PBXGroup; 200 | children = ( 201 | E6AB50A9B5D6DEF251B477CB /* Pods-RJBadgeKit_Example.debug.xcconfig */, 202 | DCA2EF8D8FA5BE88C7574C6E /* Pods-RJBadgeKit_Example.release.xcconfig */, 203 | F4A5749C6C7DE87426F053B7 /* Pods-RJBadgeKit_Tests.debug.xcconfig */, 204 | 26DDFFA3B26F1ABE8A296A1F /* Pods-RJBadgeKit_Tests.release.xcconfig */, 205 | ); 206 | name = Pods; 207 | sourceTree = ""; 208 | }; 209 | /* End PBXGroup section */ 210 | 211 | /* Begin PBXNativeTarget section */ 212 | 6003F589195388D20070C39A /* RJBadgeKit_Example */ = { 213 | isa = PBXNativeTarget; 214 | buildConfigurationList = 6003F5BF195388D20070C39A /* Build configuration list for PBXNativeTarget "RJBadgeKit_Example" */; 215 | buildPhases = ( 216 | D8B5F42091E997700F548D0B /* [CP] Check Pods Manifest.lock */, 217 | 6003F586195388D20070C39A /* Sources */, 218 | 6003F587195388D20070C39A /* Frameworks */, 219 | 6003F588195388D20070C39A /* Resources */, 220 | 81C8C47097FA3DAB0729D8EF /* [CP] Embed Pods Frameworks */, 221 | ED8EB6AC6E460EFD2BF2D572 /* [CP] Copy Pods Resources */, 222 | ); 223 | buildRules = ( 224 | ); 225 | dependencies = ( 226 | ); 227 | name = RJBadgeKit_Example; 228 | productName = RJBadgeKit; 229 | productReference = 6003F58A195388D20070C39A /* RJBadgeKit_Example.app */; 230 | productType = "com.apple.product-type.application"; 231 | }; 232 | 6003F5AD195388D20070C39A /* RJBadgeKit_Tests */ = { 233 | isa = PBXNativeTarget; 234 | buildConfigurationList = 6003F5C2195388D20070C39A /* Build configuration list for PBXNativeTarget "RJBadgeKit_Tests" */; 235 | buildPhases = ( 236 | 54619BFC1372C83B9822F361 /* [CP] Check Pods Manifest.lock */, 237 | 6003F5AA195388D20070C39A /* Sources */, 238 | 6003F5AB195388D20070C39A /* Frameworks */, 239 | 6003F5AC195388D20070C39A /* Resources */, 240 | F509852CB84B9412A22B32B1 /* [CP] Embed Pods Frameworks */, 241 | 82FEA02A08CBC1D9F6A4EEBE /* [CP] Copy Pods Resources */, 242 | ); 243 | buildRules = ( 244 | ); 245 | dependencies = ( 246 | 6003F5B4195388D20070C39A /* PBXTargetDependency */, 247 | ); 248 | name = RJBadgeKit_Tests; 249 | productName = RJBadgeKitTests; 250 | productReference = 6003F5AE195388D20070C39A /* RJBadgeKit_Tests.xctest */; 251 | productType = "com.apple.product-type.bundle.unit-test"; 252 | }; 253 | /* End PBXNativeTarget section */ 254 | 255 | /* Begin PBXProject section */ 256 | 6003F582195388D10070C39A /* Project object */ = { 257 | isa = PBXProject; 258 | attributes = { 259 | CLASSPREFIX = RJ; 260 | LastUpgradeCheck = 0920; 261 | ORGANIZATIONNAME = RylanJIN; 262 | TargetAttributes = { 263 | 6003F5AD195388D20070C39A = { 264 | TestTargetID = 6003F589195388D20070C39A; 265 | }; 266 | }; 267 | }; 268 | buildConfigurationList = 6003F585195388D10070C39A /* Build configuration list for PBXProject "RJBadgeKit" */; 269 | compatibilityVersion = "Xcode 3.2"; 270 | developmentRegion = English; 271 | hasScannedForEncodings = 0; 272 | knownRegions = ( 273 | en, 274 | Base, 275 | ); 276 | mainGroup = 6003F581195388D10070C39A; 277 | productRefGroup = 6003F58B195388D20070C39A /* Products */; 278 | projectDirPath = ""; 279 | projectRoot = ""; 280 | targets = ( 281 | 6003F589195388D20070C39A /* RJBadgeKit_Example */, 282 | 6003F5AD195388D20070C39A /* RJBadgeKit_Tests */, 283 | ); 284 | }; 285 | /* End PBXProject section */ 286 | 287 | /* Begin PBXResourcesBuildPhase section */ 288 | 6003F588195388D20070C39A /* Resources */ = { 289 | isa = PBXResourcesBuildPhase; 290 | buildActionMask = 2147483647; 291 | files = ( 292 | 873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */, 293 | 71719F9F1E33DC2100824A3D /* LaunchScreen.storyboard in Resources */, 294 | 6003F5A9195388D20070C39A /* Images.xcassets in Resources */, 295 | 6003F598195388D20070C39A /* InfoPlist.strings in Resources */, 296 | ); 297 | runOnlyForDeploymentPostprocessing = 0; 298 | }; 299 | 6003F5AC195388D20070C39A /* Resources */ = { 300 | isa = PBXResourcesBuildPhase; 301 | buildActionMask = 2147483647; 302 | files = ( 303 | 6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */, 304 | ); 305 | runOnlyForDeploymentPostprocessing = 0; 306 | }; 307 | /* End PBXResourcesBuildPhase section */ 308 | 309 | /* Begin PBXShellScriptBuildPhase section */ 310 | 54619BFC1372C83B9822F361 /* [CP] Check Pods Manifest.lock */ = { 311 | isa = PBXShellScriptBuildPhase; 312 | buildActionMask = 2147483647; 313 | files = ( 314 | ); 315 | inputPaths = ( 316 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 317 | "${PODS_ROOT}/Manifest.lock", 318 | ); 319 | name = "[CP] Check Pods Manifest.lock"; 320 | outputPaths = ( 321 | "$(DERIVED_FILE_DIR)/Pods-RJBadgeKit_Tests-checkManifestLockResult.txt", 322 | ); 323 | runOnlyForDeploymentPostprocessing = 0; 324 | shellPath = /bin/sh; 325 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 326 | showEnvVarsInLog = 0; 327 | }; 328 | 81C8C47097FA3DAB0729D8EF /* [CP] Embed Pods Frameworks */ = { 329 | isa = PBXShellScriptBuildPhase; 330 | buildActionMask = 2147483647; 331 | files = ( 332 | ); 333 | inputPaths = ( 334 | "${SRCROOT}/Pods/Target Support Files/Pods-RJBadgeKit_Example/Pods-RJBadgeKit_Example-frameworks.sh", 335 | "${BUILT_PRODUCTS_DIR}/RJBadgeKit/RJBadgeKit.framework", 336 | ); 337 | name = "[CP] Embed Pods Frameworks"; 338 | outputPaths = ( 339 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RJBadgeKit.framework", 340 | ); 341 | runOnlyForDeploymentPostprocessing = 0; 342 | shellPath = /bin/sh; 343 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RJBadgeKit_Example/Pods-RJBadgeKit_Example-frameworks.sh\"\n"; 344 | showEnvVarsInLog = 0; 345 | }; 346 | 82FEA02A08CBC1D9F6A4EEBE /* [CP] Copy Pods Resources */ = { 347 | isa = PBXShellScriptBuildPhase; 348 | buildActionMask = 2147483647; 349 | files = ( 350 | ); 351 | inputPaths = ( 352 | ); 353 | name = "[CP] Copy Pods Resources"; 354 | outputPaths = ( 355 | ); 356 | runOnlyForDeploymentPostprocessing = 0; 357 | shellPath = /bin/sh; 358 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RJBadgeKit_Tests/Pods-RJBadgeKit_Tests-resources.sh\"\n"; 359 | showEnvVarsInLog = 0; 360 | }; 361 | D8B5F42091E997700F548D0B /* [CP] Check Pods Manifest.lock */ = { 362 | isa = PBXShellScriptBuildPhase; 363 | buildActionMask = 2147483647; 364 | files = ( 365 | ); 366 | inputPaths = ( 367 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 368 | "${PODS_ROOT}/Manifest.lock", 369 | ); 370 | name = "[CP] Check Pods Manifest.lock"; 371 | outputPaths = ( 372 | "$(DERIVED_FILE_DIR)/Pods-RJBadgeKit_Example-checkManifestLockResult.txt", 373 | ); 374 | runOnlyForDeploymentPostprocessing = 0; 375 | shellPath = /bin/sh; 376 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 377 | showEnvVarsInLog = 0; 378 | }; 379 | ED8EB6AC6E460EFD2BF2D572 /* [CP] Copy Pods Resources */ = { 380 | isa = PBXShellScriptBuildPhase; 381 | buildActionMask = 2147483647; 382 | files = ( 383 | ); 384 | inputPaths = ( 385 | ); 386 | name = "[CP] Copy Pods Resources"; 387 | outputPaths = ( 388 | ); 389 | runOnlyForDeploymentPostprocessing = 0; 390 | shellPath = /bin/sh; 391 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RJBadgeKit_Example/Pods-RJBadgeKit_Example-resources.sh\"\n"; 392 | showEnvVarsInLog = 0; 393 | }; 394 | F509852CB84B9412A22B32B1 /* [CP] Embed Pods Frameworks */ = { 395 | isa = PBXShellScriptBuildPhase; 396 | buildActionMask = 2147483647; 397 | files = ( 398 | ); 399 | inputPaths = ( 400 | ); 401 | name = "[CP] Embed Pods Frameworks"; 402 | outputPaths = ( 403 | ); 404 | runOnlyForDeploymentPostprocessing = 0; 405 | shellPath = /bin/sh; 406 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RJBadgeKit_Tests/Pods-RJBadgeKit_Tests-frameworks.sh\"\n"; 407 | showEnvVarsInLog = 0; 408 | }; 409 | /* End PBXShellScriptBuildPhase section */ 410 | 411 | /* Begin PBXSourcesBuildPhase section */ 412 | 6003F586195388D20070C39A /* Sources */ = { 413 | isa = PBXSourcesBuildPhase; 414 | buildActionMask = 2147483647; 415 | files = ( 416 | 6003F59E195388D20070C39A /* RJAppDelegate.m in Sources */, 417 | 94DE14D71FECDD5C00A7FCB3 /* RJDetailViewController.m in Sources */, 418 | 94DE14D41FECDD4B00A7FCB3 /* RJDemoViewController.m in Sources */, 419 | 6003F5A7195388D20070C39A /* RJViewController.m in Sources */, 420 | 6003F59A195388D20070C39A /* main.m in Sources */, 421 | ); 422 | runOnlyForDeploymentPostprocessing = 0; 423 | }; 424 | 6003F5AA195388D20070C39A /* Sources */ = { 425 | isa = PBXSourcesBuildPhase; 426 | buildActionMask = 2147483647; 427 | files = ( 428 | 6003F5BC195388D20070C39A /* Tests.m in Sources */, 429 | ); 430 | runOnlyForDeploymentPostprocessing = 0; 431 | }; 432 | /* End PBXSourcesBuildPhase section */ 433 | 434 | /* Begin PBXTargetDependency section */ 435 | 6003F5B4195388D20070C39A /* PBXTargetDependency */ = { 436 | isa = PBXTargetDependency; 437 | target = 6003F589195388D20070C39A /* RJBadgeKit_Example */; 438 | targetProxy = 6003F5B3195388D20070C39A /* PBXContainerItemProxy */; 439 | }; 440 | /* End PBXTargetDependency section */ 441 | 442 | /* Begin PBXVariantGroup section */ 443 | 6003F596195388D20070C39A /* InfoPlist.strings */ = { 444 | isa = PBXVariantGroup; 445 | children = ( 446 | 6003F597195388D20070C39A /* en */, 447 | ); 448 | name = InfoPlist.strings; 449 | sourceTree = ""; 450 | }; 451 | 6003F5B8195388D20070C39A /* InfoPlist.strings */ = { 452 | isa = PBXVariantGroup; 453 | children = ( 454 | 6003F5B9195388D20070C39A /* en */, 455 | ); 456 | name = InfoPlist.strings; 457 | sourceTree = ""; 458 | }; 459 | 71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */ = { 460 | isa = PBXVariantGroup; 461 | children = ( 462 | 71719F9E1E33DC2100824A3D /* Base */, 463 | ); 464 | name = LaunchScreen.storyboard; 465 | sourceTree = ""; 466 | }; 467 | /* End PBXVariantGroup section */ 468 | 469 | /* Begin XCBuildConfiguration section */ 470 | 6003F5BD195388D20070C39A /* Debug */ = { 471 | isa = XCBuildConfiguration; 472 | buildSettings = { 473 | ALWAYS_SEARCH_USER_PATHS = NO; 474 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 475 | CLANG_CXX_LIBRARY = "libc++"; 476 | CLANG_ENABLE_MODULES = YES; 477 | CLANG_ENABLE_OBJC_ARC = YES; 478 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 479 | CLANG_WARN_BOOL_CONVERSION = YES; 480 | CLANG_WARN_COMMA = YES; 481 | CLANG_WARN_CONSTANT_CONVERSION = YES; 482 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 483 | CLANG_WARN_EMPTY_BODY = YES; 484 | CLANG_WARN_ENUM_CONVERSION = YES; 485 | CLANG_WARN_INFINITE_RECURSION = YES; 486 | CLANG_WARN_INT_CONVERSION = YES; 487 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 488 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 489 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 490 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 491 | CLANG_WARN_STRICT_PROTOTYPES = YES; 492 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 493 | CLANG_WARN_UNREACHABLE_CODE = YES; 494 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 495 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 496 | COPY_PHASE_STRIP = NO; 497 | ENABLE_STRICT_OBJC_MSGSEND = YES; 498 | ENABLE_TESTABILITY = YES; 499 | GCC_C_LANGUAGE_STANDARD = gnu99; 500 | GCC_DYNAMIC_NO_PIC = NO; 501 | GCC_NO_COMMON_BLOCKS = YES; 502 | GCC_OPTIMIZATION_LEVEL = 0; 503 | GCC_PREPROCESSOR_DEFINITIONS = ( 504 | "DEBUG=1", 505 | "$(inherited)", 506 | ); 507 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 508 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 509 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 510 | GCC_WARN_UNDECLARED_SELECTOR = YES; 511 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 512 | GCC_WARN_UNUSED_FUNCTION = YES; 513 | GCC_WARN_UNUSED_VARIABLE = YES; 514 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 515 | ONLY_ACTIVE_ARCH = YES; 516 | SDKROOT = iphoneos; 517 | TARGETED_DEVICE_FAMILY = "1,2"; 518 | }; 519 | name = Debug; 520 | }; 521 | 6003F5BE195388D20070C39A /* Release */ = { 522 | isa = XCBuildConfiguration; 523 | buildSettings = { 524 | ALWAYS_SEARCH_USER_PATHS = NO; 525 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 526 | CLANG_CXX_LIBRARY = "libc++"; 527 | CLANG_ENABLE_MODULES = YES; 528 | CLANG_ENABLE_OBJC_ARC = YES; 529 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 530 | CLANG_WARN_BOOL_CONVERSION = YES; 531 | CLANG_WARN_COMMA = YES; 532 | CLANG_WARN_CONSTANT_CONVERSION = YES; 533 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 534 | CLANG_WARN_EMPTY_BODY = YES; 535 | CLANG_WARN_ENUM_CONVERSION = YES; 536 | CLANG_WARN_INFINITE_RECURSION = YES; 537 | CLANG_WARN_INT_CONVERSION = YES; 538 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 539 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 540 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 541 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 542 | CLANG_WARN_STRICT_PROTOTYPES = YES; 543 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 544 | CLANG_WARN_UNREACHABLE_CODE = YES; 545 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 546 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 547 | COPY_PHASE_STRIP = YES; 548 | ENABLE_NS_ASSERTIONS = NO; 549 | ENABLE_STRICT_OBJC_MSGSEND = YES; 550 | GCC_C_LANGUAGE_STANDARD = gnu99; 551 | GCC_NO_COMMON_BLOCKS = YES; 552 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 553 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 554 | GCC_WARN_UNDECLARED_SELECTOR = YES; 555 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 556 | GCC_WARN_UNUSED_FUNCTION = YES; 557 | GCC_WARN_UNUSED_VARIABLE = YES; 558 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 559 | SDKROOT = iphoneos; 560 | TARGETED_DEVICE_FAMILY = "1,2"; 561 | VALIDATE_PRODUCT = YES; 562 | }; 563 | name = Release; 564 | }; 565 | 6003F5C0195388D20070C39A /* Debug */ = { 566 | isa = XCBuildConfiguration; 567 | baseConfigurationReference = E6AB50A9B5D6DEF251B477CB /* Pods-RJBadgeKit_Example.debug.xcconfig */; 568 | buildSettings = { 569 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 570 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 571 | GCC_PREFIX_HEADER = "RJBadgeKit/RJBadgeKit-Prefix.pch"; 572 | INFOPLIST_FILE = "RJBadgeKit/RJBadgeKit-Info.plist"; 573 | MODULE_NAME = ExampleApp; 574 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}"; 575 | PRODUCT_NAME = "$(TARGET_NAME)"; 576 | WRAPPER_EXTENSION = app; 577 | }; 578 | name = Debug; 579 | }; 580 | 6003F5C1195388D20070C39A /* Release */ = { 581 | isa = XCBuildConfiguration; 582 | baseConfigurationReference = DCA2EF8D8FA5BE88C7574C6E /* Pods-RJBadgeKit_Example.release.xcconfig */; 583 | buildSettings = { 584 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 585 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 586 | GCC_PREFIX_HEADER = "RJBadgeKit/RJBadgeKit-Prefix.pch"; 587 | INFOPLIST_FILE = "RJBadgeKit/RJBadgeKit-Info.plist"; 588 | MODULE_NAME = ExampleApp; 589 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}"; 590 | PRODUCT_NAME = "$(TARGET_NAME)"; 591 | WRAPPER_EXTENSION = app; 592 | }; 593 | name = Release; 594 | }; 595 | 6003F5C3195388D20070C39A /* Debug */ = { 596 | isa = XCBuildConfiguration; 597 | baseConfigurationReference = F4A5749C6C7DE87426F053B7 /* Pods-RJBadgeKit_Tests.debug.xcconfig */; 598 | buildSettings = { 599 | BUNDLE_LOADER = "$(TEST_HOST)"; 600 | FRAMEWORK_SEARCH_PATHS = ( 601 | "$(SDKROOT)/Developer/Library/Frameworks", 602 | "$(inherited)", 603 | "$(DEVELOPER_FRAMEWORKS_DIR)", 604 | ); 605 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 606 | GCC_PREFIX_HEADER = "Tests/Tests-Prefix.pch"; 607 | GCC_PREPROCESSOR_DEFINITIONS = ( 608 | "DEBUG=1", 609 | "$(inherited)", 610 | ); 611 | INFOPLIST_FILE = "Tests/Tests-Info.plist"; 612 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}"; 613 | PRODUCT_NAME = "$(TARGET_NAME)"; 614 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/RJBadgeKit_Example.app/RJBadgeKit_Example"; 615 | WRAPPER_EXTENSION = xctest; 616 | }; 617 | name = Debug; 618 | }; 619 | 6003F5C4195388D20070C39A /* Release */ = { 620 | isa = XCBuildConfiguration; 621 | baseConfigurationReference = 26DDFFA3B26F1ABE8A296A1F /* Pods-RJBadgeKit_Tests.release.xcconfig */; 622 | buildSettings = { 623 | BUNDLE_LOADER = "$(TEST_HOST)"; 624 | FRAMEWORK_SEARCH_PATHS = ( 625 | "$(SDKROOT)/Developer/Library/Frameworks", 626 | "$(inherited)", 627 | "$(DEVELOPER_FRAMEWORKS_DIR)", 628 | ); 629 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 630 | GCC_PREFIX_HEADER = "Tests/Tests-Prefix.pch"; 631 | INFOPLIST_FILE = "Tests/Tests-Info.plist"; 632 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}"; 633 | PRODUCT_NAME = "$(TARGET_NAME)"; 634 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/RJBadgeKit_Example.app/RJBadgeKit_Example"; 635 | WRAPPER_EXTENSION = xctest; 636 | }; 637 | name = Release; 638 | }; 639 | /* End XCBuildConfiguration section */ 640 | 641 | /* Begin XCConfigurationList section */ 642 | 6003F585195388D10070C39A /* Build configuration list for PBXProject "RJBadgeKit" */ = { 643 | isa = XCConfigurationList; 644 | buildConfigurations = ( 645 | 6003F5BD195388D20070C39A /* Debug */, 646 | 6003F5BE195388D20070C39A /* Release */, 647 | ); 648 | defaultConfigurationIsVisible = 0; 649 | defaultConfigurationName = Release; 650 | }; 651 | 6003F5BF195388D20070C39A /* Build configuration list for PBXNativeTarget "RJBadgeKit_Example" */ = { 652 | isa = XCConfigurationList; 653 | buildConfigurations = ( 654 | 6003F5C0195388D20070C39A /* Debug */, 655 | 6003F5C1195388D20070C39A /* Release */, 656 | ); 657 | defaultConfigurationIsVisible = 0; 658 | defaultConfigurationName = Release; 659 | }; 660 | 6003F5C2195388D20070C39A /* Build configuration list for PBXNativeTarget "RJBadgeKit_Tests" */ = { 661 | isa = XCConfigurationList; 662 | buildConfigurations = ( 663 | 6003F5C3195388D20070C39A /* Debug */, 664 | 6003F5C4195388D20070C39A /* Release */, 665 | ); 666 | defaultConfigurationIsVisible = 0; 667 | defaultConfigurationName = Release; 668 | }; 669 | /* End XCConfigurationList section */ 670 | }; 671 | rootObject = 6003F582195388D10070C39A /* Project object */; 672 | } 673 | -------------------------------------------------------------------------------- /Example/RJBadgeKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/RJBadgeKit.xcodeproj/xcshareddata/xcschemes/RJBadgeKit-Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 68 | 74 | 75 | 76 | 77 | 78 | 79 | 85 | 87 | 93 | 94 | 95 | 96 | 98 | 99 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /Example/RJBadgeKit.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/RJBadgeKit.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/RJBadgeKit/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Example/RJBadgeKit/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 32 | 39 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 74 | 80 | 90 | 98 | 105 | 114 | 122 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 214 | 221 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 271 | 278 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | -------------------------------------------------------------------------------- /Example/RJBadgeKit/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /Example/RJBadgeKit/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/RJBadgeKit/Images.xcassets/badgeNew.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "badgeNew@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "badgeNew@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Example/RJBadgeKit/Images.xcassets/badgeNew.imageset/badgeNew@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjinxx/RJBadgeKit/16a167202658a035910fdc42dba1d215f53f9abd/Example/RJBadgeKit/Images.xcassets/badgeNew.imageset/badgeNew@2x.png -------------------------------------------------------------------------------- /Example/RJBadgeKit/Images.xcassets/badgeNew.imageset/badgeNew@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjinxx/RJBadgeKit/16a167202658a035910fdc42dba1d215f53f9abd/Example/RJBadgeKit/Images.xcassets/badgeNew.imageset/badgeNew@3x.png -------------------------------------------------------------------------------- /Example/RJBadgeKit/RJAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // RJAppDelegate.h 3 | // RJBadgeKit 4 | // 5 | // Created by RylanJIN on 12/22/2017. 6 | // Copyright (c) 2017 RylanJIN. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface RJAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Example/RJBadgeKit/RJAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // RJAppDelegate.m 3 | // RJBadgeKit 4 | // 5 | // Created by RylanJIN on 12/22/2017. 6 | // Copyright (c) 2017 RylanJIN. All rights reserved. 7 | // 8 | 9 | #import "RJAppDelegate.h" 10 | #import "RJBadgeKit.h" 11 | 12 | @implementation RJAppDelegate 13 | 14 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 15 | { 16 | // Override point for customization after application launch. 17 | UITabBarController *tabVC = (UITabBarController *)self.window.rootViewController; 18 | UITabBarItem *more = tabVC.tabBar.items[1]; 19 | 20 | NSString *demoPath = @"root.pbdemo"; 21 | 22 | [RJBadgeController setBadgeForKeyPath:demoPath]; 23 | 24 | // set tab bar item red dot 25 | [self.badgeController observePath:demoPath badgeView:more block:nil]; 26 | 27 | return YES; 28 | } 29 | 30 | - (void)applicationWillResignActive:(UIApplication *)application 31 | { 32 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 33 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 34 | } 35 | 36 | - (void)applicationDidEnterBackground:(UIApplication *)application 37 | { 38 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 39 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 40 | } 41 | 42 | - (void)applicationWillEnterForeground:(UIApplication *)application 43 | { 44 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 45 | } 46 | 47 | - (void)applicationDidBecomeActive:(UIApplication *)application 48 | { 49 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 50 | } 51 | 52 | - (void)applicationWillTerminate:(UIApplication *)application 53 | { 54 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 55 | } 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /Example/RJBadgeKit/RJBadgeKit-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Example/RJBadgeKit/RJBadgeKit-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | @import UIKit; 15 | @import Foundation; 16 | #endif 17 | -------------------------------------------------------------------------------- /Example/RJBadgeKit/RJDemoViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RJDemoViewController.h 3 | // RJBadgeKit_Example 4 | // 5 | // Created by Ryan Jin on 22/12/2017. 6 | // Copyright © 2017 RylanJIN. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RJDemoViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/RJBadgeKit/RJDemoViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // RJDemoViewController.m 3 | // RJBadgeKit_Example 4 | // 5 | // Created by Ryan Jin on 22/12/2017. 6 | // Copyright © 2017 RylanJIN. All rights reserved. 7 | // 8 | 9 | #import "RJDemoViewController.h" 10 | #import "RJBadgeKit.h" 11 | 12 | NSString * const RJMarkPath = @"root.mark"; 13 | 14 | @interface RJDemoViewController () 15 | 16 | @property (weak, nonatomic) IBOutlet UIButton *pageButton; 17 | 18 | @end 19 | 20 | @implementation RJDemoViewController 21 | 22 | - (void)viewDidLoad 23 | { 24 | [super viewDidLoad]; 25 | // Do any additional setup after loading the view. 26 | NSString *demoPath = @"root.pbdemo.page"; 27 | 28 | [RJBadgeController setBadgeForKeyPath:demoPath]; 29 | 30 | [self.badgeController observePath:demoPath badgeView:self.pageButton block:nil]; 31 | 32 | UIButton *mark = [[UIButton alloc] initWithFrame:CGRectMake(0.0f, 12.0f, 25, 25.f)]; 33 | mark.badgeOffset = CGPointMake(-2, 6); 34 | 35 | [RJBadgeController setBadgeForKeyPath:RJMarkPath]; 36 | 37 | [self.badgeController observePath:RJMarkPath badgeView:mark block:nil]; 38 | 39 | [mark setTitle:@"Mark" forState:UIControlStateNormal]; 40 | [mark setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 41 | [mark addTarget:self action:@selector(markAction:) forControlEvents:(UIControlEventTouchUpInside)]; 42 | 43 | UIBarButtonItem *barItem = [[UIBarButtonItem alloc] initWithCustomView:mark]; 44 | self.navigationItem.rightBarButtonItem = barItem; 45 | } 46 | 47 | - (void)viewDidAppear:(BOOL)animated 48 | { 49 | [super viewDidAppear:animated]; 50 | /** 51 | @note Example for refresh badge display of -'mark' button on navigation bar, 52 | which may not appear at first due to autolayout procedure of navigation items. 53 | */ 54 | [self.badgeController refreshBadgeView]; 55 | } 56 | 57 | - (void)markAction:(UIButton *)sender 58 | { 59 | BOOL needShow = [RJBadgeController statusForKeyPath:RJMarkPath]; 60 | if (needShow) { 61 | [RJBadgeController clearBadgeForKeyPath:RJMarkPath]; 62 | } else { 63 | [RJBadgeController setBadgeForKeyPath:RJMarkPath]; 64 | } 65 | } 66 | 67 | - (void)didReceiveMemoryWarning { 68 | [super didReceiveMemoryWarning]; 69 | // Dispose of any resources that can be recreated. 70 | } 71 | 72 | /* 73 | #pragma mark - Navigation 74 | 75 | // In a storyboard-based application, you will often want to do a little preparation before navigation 76 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 77 | // Get the new view controller using [segue destinationViewController]. 78 | // Pass the selected object to the new view controller. 79 | } 80 | */ 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /Example/RJBadgeKit/RJDetailViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RJDetailViewController.h 3 | // RJBadgeKit_Example 4 | // 5 | // Created by Ryan Jin on 22/12/2017. 6 | // Copyright © 2017 RylanJIN. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RJDetailViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/RJBadgeKit/RJDetailViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // RJDetailViewController.m 3 | // RJBadgeKit_Example 4 | // 5 | // Created by Ryan Jin on 22/12/2017. 6 | // Copyright © 2017 RylanJIN. All rights reserved. 7 | // 8 | 9 | #import "RJDetailViewController.h" 10 | #import "RJBadgeKit.h" 11 | 12 | NSString * const RJItemPath1 = @"root.pbdemo.page.item1"; 13 | NSString * const RJItemPath2 = @"root.pbdemo.page.item2"; 14 | 15 | @interface RJDetailViewController () 16 | 17 | @property (weak, nonatomic) IBOutlet UIButton *item1; 18 | @property (weak, nonatomic) IBOutlet UIButton *item2; 19 | 20 | @end 21 | 22 | @implementation RJDetailViewController 23 | 24 | - (void)viewDidLoad 25 | { 26 | [super viewDidLoad]; 27 | // Do any additional setup after loading the view. 28 | [RJBadgeController setBadgeForKeyPath:RJItemPath1]; 29 | [RJBadgeController setBadgeForKeyPath:RJItemPath2]; 30 | 31 | [self.badgeController observePath:RJItemPath1 badgeView:self.item1 block:nil]; 32 | [self.badgeController observePath:RJItemPath2 badgeView:self.item2 block:nil]; 33 | 34 | [self.item1 setBadgeImage:[UIImage imageNamed:@"badgeNew"]]; 35 | } 36 | 37 | - (IBAction)clickItem1:(UIButton *)sender 38 | { 39 | BOOL needShow = [RJBadgeController statusForKeyPath:RJItemPath1]; 40 | if (needShow) { 41 | [RJBadgeController clearBadgeForKeyPath:RJItemPath1]; 42 | } else { 43 | [RJBadgeController setBadgeForKeyPath:RJItemPath1]; 44 | } 45 | } 46 | 47 | - (IBAction)clickItem2:(UIButton *)sender 48 | { 49 | BOOL needShow = [RJBadgeController statusForKeyPath:RJItemPath2]; 50 | if (needShow) { 51 | [RJBadgeController clearBadgeForKeyPath:RJItemPath2]; 52 | } else { 53 | [RJBadgeController setBadgeForKeyPath:RJItemPath2]; 54 | } 55 | } 56 | 57 | /* 58 | #pragma mark - Navigation 59 | 60 | // In a storyboard-based application, you will often want to do a little preparation before navigation 61 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 62 | // Get the new view controller using [segue destinationViewController]. 63 | // Pass the selected object to the new view controller. 64 | } 65 | */ 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /Example/RJBadgeKit/RJViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RJViewController.h 3 | // RJBadgeKit 4 | // 5 | // Created by Ryan Jin on 12/22/2017. 6 | // Copyright (c) 2017 Ryan Jin. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface RJViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/RJBadgeKit/RJViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // RJViewController.h 3 | // RJBadgeKit 4 | // 5 | // Created by RylanJIN on 08/03/2017. 6 | // Copyright (c) 2017 RylanJIN. All rights reserved. 7 | // 8 | 9 | #import "RJViewController.h" 10 | #import "RJBadgeKit.h" 11 | 12 | NSString * const DEMO_PARENT_PATH = @"root.p365"; 13 | NSString * const DEMO_CHILD_PATH1 = @"root.p365.test1"; 14 | NSString * const DEMO_CHILD_PATH2 = @"root.p365.test2"; 15 | 16 | @interface RJViewController () 17 | 18 | @property (weak, nonatomic) IBOutlet UILabel *countLabel; 19 | @property (weak, nonatomic) IBOutlet UILabel *pathLabel; 20 | @property (weak, nonatomic) IBOutlet UITextField *countField; 21 | @property (weak, nonatomic) IBOutlet UIButton *parentButton; 22 | @property (weak, nonatomic) IBOutlet UIButton *childButton1; 23 | @property (weak, nonatomic) IBOutlet UIButton *childButton2; 24 | 25 | @end 26 | 27 | @implementation RJViewController 28 | 29 | - (void)viewDidLoad 30 | { 31 | [super viewDidLoad]; 32 | // Do any additional setup after loading the view, typically from a nib. 33 | [self.countField setDelegate:self]; 34 | [self.countField setKeyboardType:UIKeyboardTypeNumberPad]; 35 | 36 | [self.pathLabel setText:DEMO_CHILD_PATH1]; 37 | 38 | // self.parentButton.badgeOffset = CGPointMake(-50, 0); 39 | self.parentButton.badgeRadius = 5.f; 40 | self.parentButton.badgeBgColor = [UIColor blueColor]; 41 | 42 | // observe parent button 'root.p365' 43 | [self.badgeController observePath:DEMO_PARENT_PATH 44 | badgeView:self.parentButton 45 | block:^(id observer, NSDictionary *info) { 46 | NSLog(@"root.p365 => %@", info); 47 | }]; 48 | 49 | // observe child button 'root.p365.test1' 50 | [self.badgeController observePath:DEMO_CHILD_PATH1 51 | badgeView:self.childButton1 52 | block:^(RJViewController *observer, NSDictionary *info) { 53 | NSUInteger count = [info[RJBadgeCountKey] unsignedIntegerValue]; 54 | [observer.countLabel setText:[NSString stringWithFormat:@"%lu", (unsigned long)count]]; 55 | }]; 56 | 57 | NSUInteger count = [RJBadgeController countForKeyPath:DEMO_CHILD_PATH1]; 58 | [self.countLabel setText:[@(count) stringValue]]; 59 | 60 | /** 61 | DEBUG FOR PARENT BADGE COUNTING 62 | */ 63 | [RJBadgeController setBadgeForKeyPath:DEMO_CHILD_PATH2 count:2]; 64 | 65 | // observe child button 'root.p365.test2' 66 | [self.badgeController observePath:DEMO_CHILD_PATH2 badgeView:self.childButton2 block:nil]; 67 | } 68 | 69 | #pragma mark - Click Button 70 | - (IBAction)setBadgePathWithCount:(UIButton *)sender 71 | { 72 | [self.view endEditing:YES]; 73 | 74 | if (!self.countField.text) return; 75 | 76 | [RJBadgeController setBadgeForKeyPath:DEMO_CHILD_PATH1 77 | count:[self.countField.text integerValue]]; 78 | } 79 | 80 | - (IBAction)setBadgePath:(UIButton *)sender { 81 | [RJBadgeController setBadgeForKeyPath:DEMO_CHILD_PATH1]; 82 | } 83 | 84 | - (IBAction)clearBadgePath:(UIButton *)sender { 85 | [RJBadgeController clearBadgeForKeyPath:DEMO_CHILD_PATH1]; 86 | } 87 | 88 | - (IBAction)clickChildButton1:(UIButton *)sender 89 | { 90 | BOOL needShow = [RJBadgeController statusForKeyPath:DEMO_CHILD_PATH1]; 91 | if (needShow) { 92 | [RJBadgeController clearBadgeForKeyPath:DEMO_CHILD_PATH1]; 93 | } else { 94 | [RJBadgeController setBadgeForKeyPath:DEMO_CHILD_PATH1]; 95 | } 96 | } 97 | 98 | - (IBAction)clickChildButton2:(UIButton *)sender 99 | { 100 | BOOL needShow = [RJBadgeController statusForKeyPath:DEMO_CHILD_PATH2]; 101 | if (needShow) { 102 | [RJBadgeController clearBadgeForKeyPath:DEMO_CHILD_PATH2]; 103 | } else { 104 | [RJBadgeController setBadgeForKeyPath:DEMO_CHILD_PATH2 count:2]; 105 | } 106 | } 107 | 108 | - (IBAction)clickParentButton:(UIButton *)sender { 109 | [RJBadgeController clearBadgeForKeyPath:DEMO_PARENT_PATH forced:YES]; 110 | } 111 | 112 | #pragma mark - UITextFieldDelegate 113 | - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range 114 | replacementString:(NSString *)string { 115 | return [self validateNumber:string]; 116 | } 117 | 118 | - (BOOL)validateNumber:(NSString *)number 119 | { 120 | BOOL res = YES; 121 | int i = 0; 122 | 123 | NSCharacterSet *tmpSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789"]; 124 | 125 | while (i < number.length) { 126 | NSString * string = [number substringWithRange:NSMakeRange(i, 1)]; 127 | NSRange range = [string rangeOfCharacterFromSet:tmpSet]; 128 | if (range.length == 0) { res = NO; break; } 129 | 130 | i++; 131 | } 132 | return res; 133 | } 134 | 135 | @end 136 | -------------------------------------------------------------------------------- /Example/RJBadgeKit/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/RJBadgeKit/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // RJBadgeKit 4 | // 5 | // Created by RylanJIN on 12/22/2017. 6 | // Copyright (c) 2017 RylanJIN. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | #import "RJAppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) 13 | { 14 | @autoreleasepool { 15 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([RJAppDelegate class])); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Example/Tests/Tests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Example/Tests/Tests-Prefix.pch: -------------------------------------------------------------------------------- 1 | // The contents of this file are implicitly included at the beginning of every test case source file. 2 | 3 | #ifdef __OBJC__ 4 | 5 | 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /Example/Tests/Tests.m: -------------------------------------------------------------------------------- 1 | // 2 | // RJBadgeKitTests.m 3 | // RJBadgeKitTests 4 | // 5 | // Created by RylanJIN on 12/22/2017. 6 | // Copyright (c) 2017 RylanJIN. All rights reserved. 7 | // 8 | 9 | @import XCTest; 10 | 11 | @interface Tests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation Tests 16 | 17 | - (void)setUp 18 | { 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 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | 36 | -------------------------------------------------------------------------------- /Example/Tests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjinxx/RJBadgeKit/16a167202658a035910fdc42dba1d215f53f9abd/Example/demo.gif -------------------------------------------------------------------------------- /Example/path.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjinxx/RJBadgeKit/16a167202658a035910fdc42dba1d215f53f9abd/Example/path.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 RylanJIN 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RJBadgeKit 2 | 3 | [![CI Status](http://img.shields.io/travis/RylanJIN/RJBadgeKit.svg?style=flat)](https://travis-ci.org/RylanJIN/RJBadgeKit) 4 | [![Version](https://img.shields.io/cocoapods/v/RJBadgeKit.svg?style=flat)](http://cocoapods.org/pods/RJBadgeKit) 5 | [![License](https://img.shields.io/cocoapods/l/RJBadgeKit.svg?style=flat)](http://cocoapods.org/pods/RJBadgeKit) 6 | [![Platform](https://img.shields.io/cocoapods/p/RJBadgeKit.svg?style=flat)](http://cocoapods.org/pods/RJBadgeKit) 7 | 8 | ## Example 9 | 10 | To run the example project, clone the repo, and run `pod install` from the Example directory first. 11 | 12 | ## Installation 13 | 14 | RJBadgeKit is available through [CocoaPods](http://cocoapods.org). To install 15 | it, simply add the following line to your Podfile: 16 | 17 | ```ruby 18 | pod 'RJBadgeKit' 19 | ``` 20 | 21 | ## Introduction 22 | 23 | This is the code repository associated with blog article: https://juejin.im/post/5b80265de51d4538a31b4165 24 | 25 | RJBadgeKit是一套完整的小红点(消息推送提示)解决方案,使用场景为App某个功能块有内容更新或有未读消息时右上角会有小红点提示。RJBadgeKit支持**小红点**和**数字**显示两种形式,小红点也可以是**自定义图片**。 另外,提供多层级小红点的关联显示逻辑,比如微信tab上的小红点显示数字为聊天列表里未读消息的总和,只有所有未读消息都清空的情况下tab上的小红点才会消失。 26 | 27 | ![image](https://github.com/RylanJIN/RJBadgeKit/blob/master/Example/demo.gif) 28 | 29 | RJBadgeKit的小红点所支持的路径格式为`root.xx.xx`, 小红点原则是父节点的小红点为子节点的小红点并集。root为默认的根路径。如下图所示,root.first为子路径,root.second为同级子路径。在纯红点模式下,root的小红点显示为root.first, root.second和root.third的并集,同理在数字显示模式下,root的badge数量为root.first, root.second和root.third的badge数量之和。而root.first的badge数量则又为root.first.firstA和root.first.firstB的和。 30 | 31 | ![image](https://github.com/RylanJIN/RJBadgeKit/blob/master/Example/path.png) 32 | 33 | ## Useage 34 | 35 | RJBadgeKit的用法包括**a)** add observer **b)** set/clear badge **c)** show/hide badge, 接口分别如下所示: 36 | 37 | #### Add observer 38 | 39 | 假设我们有个促销页面,该促销有两个商品参与活动,则促销页面的路径可设置为root.promotion,促销页面内两个商品的路径分别设为root.promotion.item1, root.promotion.item2. 现在需要推送小红点消息给用户,在promotion的入口处的button需要显示小红点提示,当用户进入到promotion页面且分别点击了item1和item2后,promotion的小红点提示才消失。 40 | 41 | 首先我们在RJPromotionViewController里面对promotionButton添加路径的观察者,当该路径被set badge时候则显示小红点,clear badge时则隐藏小红点: 42 | 43 | ``` 44 | [self.badgeController observePath:@"root.promotion" 45 |                       badgeView:promotionButton 46 |                            block:^(RJPromotionViewController *observer, NSDictionary *info) { 47 |    // Use [observer doSomething] instead of [self doSomething] to avoid retain cycle in block 48 |    // key path     -> info[RJBadgePathKey] : badgeContoller所observe的路径 49 |    // badge status -> info[RJBadgeShowKey] : 当前路径所对应的badge是否处于set状态(是否应该显示小红点) 50 |    // badge count  -> info[RJBadgeCountKey]: 当前路径所对应的badge数值(仅在badge为数值模式下有效) 51 | }]; 52 | ``` 53 | 54 | 这里需要注意的几点是: 55 | 56 | 1. self.badgeController为动态生成的属性,无需自己定义和初始化,RJBadgeKit为所有NSObject对象通过category添加了badgeController 57 | 2. 无需调用remove observer, RJBadgeKit通过自释放机制自动移除observer. 如果确实需要提前移除观察者,可以调用unobservePath接口 58 | 3. 为防止循环引用,在badge的block里面用参数observer来代替self, RJBadgeKit对observer(即self.badgeController的self)进行了weak化处理并通过block回调参数传出 59 | 60 | #### Set/clear badge 61 | 62 | 在上述例子中,当网络请求返回时发现有两个促销数据,则调用: 63 | 64 | ``` 65 | [RJBadgeController setBadgeForKeyPath:@"root.promotion.item1"]; 66 | [RJBadgeController setBadgeForKeyPath:@"root.promotion.item2"]; 67 | ``` 68 | 69 | 子节点的badge状态变化会触发父节点observe的block回调,所以上述两行代码执行后promotionButton会触发显示小红点。当然如果希望promotionButton不显示小红点,而是显示具体的促销数量,则可以直接如下调用: 70 | 71 | ``` 72 | [RJBadgeController setBadgeForKeyPath:@"root.promotion" count:2]; 73 | ``` 74 | 75 | 如果promotion item下面还有子节点, 则调用: 76 | 77 | ``` 78 | [RJBadgeController setBadgeForKeyPath:@"root.promotion.item1" count:5]; 79 | ``` 80 | 81 | 在这个情况下,promotionButton上显示的数值(亦即root.promotion路径对应的badge值)为root.promotion.item1和root.promotion.item2及其所有子节点的数值之和。当用户点击查看item1和item2后,分别调用clear badeg接口: 82 | 83 | ``` 84 | [RJBadgeController clearBadgeForKeyPath:@"root.promotion.item1"]; 85 | [RJBadgeController clearBadgeForKeyPath:@"root.promotion.item2"]; 86 | ``` 87 | 88 | 这时父节点root.promotion的badge自动clear, promotionButton的小红点会自动隐藏。如果希望在item1被clear后就强制清除root.promotion的badge, 则可以在clear item1后调用: 89 | 90 | ``` 91 | [RJBadgeController clearBadgeForKeyPath:@"root.promotion" force:YES]; 92 | ``` 93 | 94 | 这样即使子节点的badge尚未全部清除,父节点也会被强制clear. P.S 正常情况下不应该去调用force:YES, 如果非要调用,可能是路径结构设计不合理了。 95 | 96 | #### Show/hide badge 97 | 98 | RJBadgeKit支持UIView, UITabBarItem和UIBarButtonItem的小红点显示。小红点类型则支持默认圆形小红点,数值和自定义view/图片。显示的优先级为number > custom view > red dot 99 | 100 | ``` 101 | promotionButton.badgeOffset = CGPointMake(-50, 0); // 调整小红点的显示位置offset, 相对于右上角 102 | 103 | [self.promotionButton setBadgeImage:[UIImage imageNamed:@"badgeNew"]]; // 显示自定义的badge icon 104 | 105 | [self.promotionButton setCustomView:self.customBadgeView]; // 显示自定义的badge view 106 | ``` 107 | 108 | 更详细的使用示例请参考RJBadgeKit的Example工程 109 | 110 | ## Author 111 | 112 | Ryan Jin, xiaojun.jin@outlook.com 113 | 114 | ## License 115 | 116 | RJBadgeKit is available under the MIT license. See the LICENSE file for more info. 117 | -------------------------------------------------------------------------------- /RJBadgeKit.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint RJBadgeKit.podspec' to ensure this is a 3 | # valid spec before submitting. 4 | # 5 | # Any lines starting with a # are optional, but their use is encouraged 6 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | s.name = 'RJBadgeKit' 11 | s.version = '0.2.5' 12 | s.summary = 'Red dot (version/message reminder) display and its management.' 13 | 14 | # This description is used to generate tags and improve search results. 15 | # * Think: What does it do? Why did you write it? What is the focus? 16 | # * Try to keep it short, snappy and to the point. 17 | # * Write the description between the DESC delimiters below. 18 | # * Finally, don't worry about the indent, CocoaPods strips it! 19 | 20 | s.description = <<-DESC 21 | A complete and lightweight solution for red dot (version/message reminder) display and its management. 22 | DESC 23 | 24 | s.homepage = 'https://github.com/RylanJIN/RJBadgeKit' 25 | # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2' 26 | s.license = { :type => 'MIT', :file => 'LICENSE' } 27 | s.author = { 'Ryan Jin' => 'xiaojun.jin@outlook.com' } 28 | s.source = { :git => 'https://github.com/RylanJIN/RJBadgeKit.git', :tag => s.version.to_s } 29 | # s.social_media_url = 'https://twitter.com/' 30 | 31 | s.ios.deployment_target = '8.0' 32 | 33 | s.source_files = 'RJBadgeKit/Classes/**/*' 34 | 35 | # s.resource_bundles = { 36 | # 'RJBadgeKit' => ['RJBadgeKit/Assets/*.png'] 37 | # } 38 | 39 | # s.public_header_files = 'Pod/Classes/**/*.h' 40 | # s.frameworks = 'UIKit', 'MapKit' 41 | # s.dependency 'AFNetworking', '~> 2.3' 42 | end 43 | -------------------------------------------------------------------------------- /RJBadgeKit/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjinxx/RJBadgeKit/16a167202658a035910fdc42dba1d215f53f9abd/RJBadgeKit/Assets/.gitkeep -------------------------------------------------------------------------------- /RJBadgeKit/Classes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjinxx/RJBadgeKit/16a167202658a035910fdc42dba1d215f53f9abd/RJBadgeKit/Classes/.gitkeep -------------------------------------------------------------------------------- /RJBadgeKit/Classes/BadgeController/NSObject+RJBadgeController.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+RJBadgeController.h 3 | // RJBadgeKit 4 | // 5 | // Created by Ryan Jin on 06/12/2017. 6 | // 7 | 8 | #import 9 | #import "RJBadgeController.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NSObject (RJBadgeController) 14 | 15 | @property (nonatomic, strong) RJBadgeController *badgeController; 16 | 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /RJBadgeKit/Classes/BadgeController/NSObject+RJBadgeController.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+RJBadgeController.m 3 | // RJBadgeKit 4 | // 5 | // Created by Ryan Jin on 06/12/2017. 6 | // 7 | 8 | #import "NSObject+RJBadgeController.h" 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | static void * NSObjectBadgeControllerKey = &NSObjectBadgeControllerKey; 14 | 15 | @implementation NSObject (RJBadgeController) 16 | 17 | - (RJBadgeController *)badgeController 18 | { 19 | id controller = objc_getAssociatedObject(self, NSObjectBadgeControllerKey); 20 | // lazily create the badgeController 21 | if (nil == controller) { 22 | controller = [RJBadgeController controllerWithObserver:self]; 23 | self.badgeController = controller; 24 | } 25 | return controller; 26 | } 27 | 28 | - (void)setBadgeController:(RJBadgeController *)badgeController { 29 | objc_setAssociatedObject(self, NSObjectBadgeControllerKey, badgeController, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 30 | } 31 | 32 | @end 33 | 34 | NS_ASSUME_NONNULL_END 35 | -------------------------------------------------------------------------------- /RJBadgeKit/Classes/BadgeController/RJBadgeController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RJBadgeController.h 3 | // RJBadgeKit 4 | // 5 | // Created by Ryan Jin on 06/12/2017. 6 | // 7 | 8 | #import 9 | #import "RJBadgeView.h" 10 | #import "RJBadge.h" 11 | 12 | #ifndef RJBadgeKeyPath 13 | #define RJBadgeKeyPath(KEYPATH) \ 14 | @(((void)(NO && ((void)KEYPATH, NO)), strchr(#KEYPATH, '.') + 1)) 15 | #endif 16 | 17 | #ifndef RJBadgeClassKeyPath 18 | #define RJBadgeClassKeyPath(CLASS, KEYPATH) \ 19 | @(((void)(NO && ((void)((CLASS *)(nil)).KEYPATH, NO)), #KEYPATH)) 20 | #endif 21 | 22 | NS_ASSUME_NONNULL_BEGIN 23 | 24 | extern NSString * const RJBadgePathKey; 25 | extern NSString * const RJBadgeCountKey; 26 | extern NSString * const RJBadgeShowKey; 27 | 28 | typedef void (^RJBadgeNotificationBlock)(id _Nullable observer, NSDictionary *info); 29 | 30 | @interface RJBadgeController : NSObject 31 | 32 | /** 33 | The observer notified on badge change. Specified on initialization. 34 | */ 35 | @property (nullable, nonatomic, weak, readonly) id observer; 36 | 37 | #pragma mark - Initialize 38 | 39 | + (instancetype)controllerWithObserver:(nullable id)observer; 40 | 41 | - (instancetype)initWithObserver:(nullable id)observer NS_DESIGNATED_INITIALIZER; 42 | 43 | /** 44 | @abstract Initializes a new instance. 45 | @warning This method is unavaialble. Use 'initWithObserver:' instead. 46 | */ 47 | + (instancetype)new NS_UNAVAILABLE; 48 | 49 | /** 50 | @abstract Initializes a new instance. 51 | @warning This method is unavaialble. Use 'initWithObserver:' instead. 52 | */ 53 | - (instancetype)init NS_UNAVAILABLE; 54 | 55 | #pragma mark - Observe 56 | 57 | - (void)observePath:(NSString *)keyPath block:(RJBadgeNotificationBlock)block; 58 | 59 | - (void)observePath:(NSString *)keyPath badgeView:(nullable id)badgeView block:(nullable RJBadgeNotificationBlock)block; 60 | 61 | - (void)observePaths:(NSArray *)keyPaths block:(RJBadgeNotificationBlock)block; 62 | 63 | #pragma mark - Unobserve 64 | 65 | - (void)unobservePath:(NSString *)keyPath; 66 | 67 | - (void)unobserveAll; 68 | 69 | #pragma mark - Operation 70 | 71 | /** 72 | refresh all badge views associated with current -observer, 73 | aim to deal with situations / issue linked to auto-layout, 74 | e.g. set 'setBadgeForKeyPath' when layout hasn't done yet. 75 | */ 76 | - (void)refreshBadgeView; 77 | 78 | + (void)setBadgeForKeyPath:(NSString *)keyPath; 79 | + (void)setBadgeForKeyPath:(NSString *)keyPath count:(NSUInteger)count; 80 | 81 | + (void)clearBadgeForKeyPath:(NSString *)keyPath; 82 | + (void)clearBadgeForKeyPath:(NSString *)keyPath forced:(BOOL)forced; 83 | 84 | + (BOOL)statusForKeyPath:(NSString *)keyPath; 85 | 86 | + (NSUInteger)countForKeyPath:(NSString *)keyPath; 87 | 88 | @end 89 | 90 | NS_ASSUME_NONNULL_END 91 | -------------------------------------------------------------------------------- /RJBadgeKit/Classes/BadgeController/RJBadgeController.m: -------------------------------------------------------------------------------- 1 | // 2 | // RJBadgeController.m 3 | // RJBadgeKit 4 | // 5 | // Created by Ryan Jin on 06/12/2017. 6 | // 7 | 8 | #import "RJBadgeController.h" 9 | #import "RJBadgeInfo.h" 10 | #import 11 | #import "RJBadgeManager.h" 12 | 13 | @interface RJBadgeController () 14 | 15 | @property (nullable, nonatomic, weak) id observer; 16 | 17 | @end 18 | 19 | @implementation RJBadgeController { 20 | NSHashTable *_infos; 21 | pthread_mutex_t _lock; 22 | } 23 | 24 | #pragma mark - Lifecycle 25 | 26 | - (instancetype)initWithObserver:(nullable id)observer 27 | { 28 | self = [super init]; 29 | if (self) { 30 | _infos = [[NSHashTable alloc] initWithOptions:NSPointerFunctionsStrongMemory | 31 | NSPointerFunctionsObjectPersonality 32 | capacity:0]; 33 | pthread_mutex_init(&_lock, NULL); 34 | self.observer = observer; 35 | } 36 | return self; 37 | } 38 | 39 | + (instancetype)controllerWithObserver:(nullable id)observer { 40 | return [[self alloc] initWithObserver:observer]; 41 | } 42 | 43 | - (void)dealloc 44 | { 45 | [self unobserveAll]; 46 | pthread_mutex_destroy(&_lock); 47 | } 48 | 49 | #pragma mark - Observe 50 | 51 | - (void)observePath:(NSString *)keyPath block:(RJBadgeNotificationBlock)block 52 | { 53 | NSAssert(0 != keyPath.length && NULL != block, @"missing required parameters: keyPath:%@ block:%p", keyPath, block); 54 | 55 | if (0 == keyPath.length || NULL == block) return; 56 | 57 | // create info 58 | RJBadgeInfo *info = [[RJBadgeInfo alloc] initWithController:self keyPath:keyPath block:block]; 59 | 60 | // observe object with info 61 | [self _observeWithInfo:info]; 62 | } 63 | 64 | - (void)observePath:(NSString *)keyPath badgeView:(nullable id)badgeView block:(nullable RJBadgeNotificationBlock)block 65 | { 66 | NSAssert(0 != keyPath.length, @"missing required parameters: keyPath:%@", keyPath); 67 | 68 | if (0 == keyPath.length) return; 69 | 70 | // create info 71 | RJBadgeInfo *info = [[RJBadgeInfo alloc] initWithController:self keyPath:keyPath badgeView:badgeView block:block]; 72 | 73 | // observe object with info 74 | [self _observeWithInfo:info]; 75 | } 76 | 77 | - (void)observePaths:(NSArray *)keyPaths block:(RJBadgeNotificationBlock)block 78 | { 79 | NSAssert(0 != keyPaths.count && NULL != block, @"missing required parameters: keyPaths:%@ block:%p", keyPaths, block); 80 | 81 | if (0 == keyPaths.count || NULL == block) return; 82 | 83 | for (NSString *keyPath in keyPaths) { 84 | [self observePath:keyPath block:block]; 85 | } 86 | } 87 | 88 | #pragma mark - Unobserve 89 | 90 | - (void)unobservePath:(NSString *)keyPath 91 | { 92 | // create representative info 93 | RJBadgeInfo *info = [[RJBadgeInfo alloc] initWithController:self keyPath:keyPath]; 94 | 95 | // unobserve object property 96 | [self _unobserveWithInfo:info]; 97 | } 98 | 99 | - (void)unobserveAll { 100 | [self _unobserveAll]; 101 | } 102 | 103 | #pragma mark - Utilities 104 | 105 | - (void)_observeWithInfo:(RJBadgeInfo *)info 106 | { 107 | pthread_mutex_lock(&_lock); 108 | 109 | // check for info existence 110 | RJBadgeInfo *existingInfo = [_infos member:info]; 111 | 112 | if (existingInfo) { 113 | // aleady exists, don't observe again 114 | pthread_mutex_unlock(&_lock); return; 115 | } 116 | 117 | // add info and oberve 118 | [_infos addObject:info]; 119 | 120 | // unlock prior to callout 121 | pthread_mutex_unlock(&_lock); 122 | 123 | [[RJBadgeManager sharedManager] observeWithInfo:info]; 124 | } 125 | 126 | - (void)_unobserveWithInfo:(RJBadgeInfo *)info 127 | { 128 | pthread_mutex_lock(&_lock); 129 | 130 | // lookup registered info instance 131 | RJBadgeInfo *registeredInfo = [_infos member:info]; 132 | 133 | if (registeredInfo) { 134 | [_infos removeObject:registeredInfo]; 135 | } 136 | 137 | pthread_mutex_unlock(&_lock); 138 | 139 | [[RJBadgeManager sharedManager] unobserveWithInfo:info]; 140 | } 141 | 142 | - (void)_unobserveAll 143 | { 144 | pthread_mutex_lock(&_lock); 145 | 146 | NSHashTable *infos = [_infos copy]; 147 | 148 | // clear table and map 149 | [_infos removeAllObjects]; 150 | 151 | // unlock 152 | pthread_mutex_unlock(&_lock); 153 | 154 | [[RJBadgeManager sharedManager] unobserveWithInfos:infos]; 155 | } 156 | 157 | #pragma mark - Properties 158 | 159 | - (NSString *)debugDescription 160 | { 161 | NSMutableString *s = [NSMutableString stringWithFormat:@"<%@:%p", NSStringFromClass([self class]), self]; 162 | [s appendFormat:@" observer:<%@:%p>", NSStringFromClass([_observer class]), _observer]; 163 | 164 | pthread_mutex_lock(&_lock); 165 | 166 | if (0 != _infos.count) { 167 | [s appendString:@"\n "]; 168 | } 169 | 170 | NSMutableArray *infoDescriptions = [NSMutableArray arrayWithCapacity:_infos.count]; 171 | 172 | for (RJBadgeInfo *info in _infos) { 173 | [infoDescriptions addObject:info.debugDescription]; 174 | } 175 | 176 | [s appendFormat:@"-> %@", infoDescriptions]; 177 | 178 | pthread_mutex_unlock(&_lock); 179 | 180 | [s appendString:@">"]; 181 | 182 | return s; 183 | } 184 | 185 | #pragma mark - Operation 186 | 187 | - (void)refreshBadgeView { 188 | [[RJBadgeManager sharedManager] refreshBadgeWithInfos:_infos]; 189 | } 190 | 191 | + (void)setBadgeForKeyPath:(NSString *)keyPath 192 | { 193 | if (![keyPath length]) return; 194 | 195 | [[RJBadgeManager sharedManager] setBadgeForKeyPath:keyPath]; 196 | } 197 | 198 | + (void)setBadgeForKeyPath:(NSString *)keyPath count:(NSUInteger)count 199 | { 200 | if (![keyPath length]) return; 201 | 202 | [[RJBadgeManager sharedManager] setBadgeForKeyPath:keyPath count:count]; 203 | } 204 | 205 | + (void)clearBadgeForKeyPath:(NSString *)keyPath { 206 | [self clearBadgeForKeyPath:keyPath forced:NO]; 207 | } 208 | 209 | + (void)clearBadgeForKeyPath:(NSString *)keyPath forced:(BOOL)forced 210 | { 211 | if (![keyPath length]) return; 212 | 213 | [[RJBadgeManager sharedManager] clearBadgeForKeyPath:keyPath forced:forced]; 214 | } 215 | 216 | + (BOOL)statusForKeyPath:(NSString *)keyPath 217 | { 218 | if (![keyPath length]) return NO; 219 | 220 | return [[RJBadgeManager sharedManager] statusForKeyPath:keyPath]; 221 | } 222 | 223 | + (NSUInteger)countForKeyPath:(NSString *)keyPath 224 | { 225 | if (![keyPath length]) return 0; 226 | 227 | return [[RJBadgeManager sharedManager] countForKeyPath:keyPath]; 228 | } 229 | 230 | @end 231 | -------------------------------------------------------------------------------- /RJBadgeKit/Classes/BadgeController/RJBadgeManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // RJBadgeManager.h 3 | // RJBadgeKit 4 | // 5 | // Created by Ryan Jin on 06/12/2017. 6 | // 7 | 8 | #import 9 | #import "RJBadgeInfo.h" 10 | #import "RJBadgeModel.h" 11 | 12 | /** BADGE TREE PATH 13 | -root : root 14 | -first : root.first 15 | -firstA : root.first.firstA 16 | -firstB : root.first.firstB 17 | -sencond : root.second 18 | -secondA : root.second.secondA 19 | -third : root.third 20 | */ 21 | 22 | NS_ASSUME_NONNULL_BEGIN 23 | 24 | extern NSString * const RJBadgeRootPath; 25 | extern NSString * const RJBadgeNameKey; 26 | 27 | @interface RJBadgeManager : NSObject 28 | 29 | #pragma mark - Initialize 30 | 31 | + (RJBadgeManager *)sharedManager; 32 | 33 | #pragma mark - Observe 34 | 35 | - (void)observeWithInfo:(nullable RJBadgeInfo *)info; 36 | 37 | #pragma mark - Unobserve 38 | 39 | - (void)unobserveWithInfo:(nullable RJBadgeInfo *)info; 40 | 41 | - (void)unobserveWithInfos:(nullable NSHashTable *)infos; 42 | 43 | #pragma mark - Operation 44 | 45 | - (void)refreshBadgeWithInfos:(NSHashTable *)infos; 46 | 47 | - (void)setBadgeForKeyPath:(NSString *)keyPath; 48 | - (void)setBadgeForKeyPath:(NSString *)keyPath count:(NSUInteger)count; 49 | 50 | - (void)clearBadgeForKeyPath:(NSString *)keyPath; 51 | - (void)clearBadgeForKeyPath:(NSString *)keyPath forced:(BOOL)forced; 52 | 53 | - (BOOL)statusForKeyPath:(NSString *)keyPath; 54 | 55 | - (NSUInteger)countForKeyPath:(NSString *)keyPath; 56 | 57 | @end 58 | 59 | NS_ASSUME_NONNULL_END 60 | -------------------------------------------------------------------------------- /RJBadgeKit/Classes/BadgeController/RJBadgeManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // RJBadgeManager.m 3 | // RJBadgeKit 4 | // 5 | // Created by Ryan Jin on 06/12/2017. 6 | // 7 | 8 | #import "RJBadgeManager.h" 9 | #import 10 | #import "NSString+RJBadge.h" 11 | #import "UIBarButtonItem+RJBadge.h" 12 | #import "UITabBarItem+RJBadge.h" 13 | #import "UIView+RJBadge.h" 14 | #import "RJBadgeController.h" 15 | 16 | #ifndef dispatch_queue_async_rjbk 17 | #define dispatch_queue_async_rjbk(queue, block)\ 18 | if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(queue)) == 0) { \ 19 | block(); \ 20 | } else { \ 21 | dispatch_async(queue, block); \ 22 | } 23 | #endif 24 | 25 | #ifndef dispatch_main_async_rjbk 26 | #define dispatch_main_async_rjbk(block) dispatch_queue_async_rjbk(dispatch_get_main_queue(), block) 27 | #endif 28 | 29 | NS_ASSUME_NONNULL_BEGIN 30 | 31 | @implementation RJBadgeManager { 32 | NSMutableDictionary *> *_objectInfosMap; 33 | RJBadgeModel *_root; 34 | pthread_mutex_t _mutex; 35 | dispatch_queue_t _badgeQueue; 36 | } 37 | 38 | #pragma mark - Lifecycle 39 | 40 | + (RJBadgeManager *)sharedManager 41 | { 42 | static RJBadgeManager *_badgeMgr; 43 | static dispatch_once_t onceToken; 44 | dispatch_once(&onceToken, ^{ 45 | _badgeMgr = [RJBadgeManager new]; 46 | }); 47 | 48 | return _badgeMgr; 49 | } 50 | 51 | - (instancetype)init 52 | { 53 | self = [super init]; 54 | if (nil != self) { 55 | // recursive lock 56 | pthread_mutexattr_t attr; 57 | pthread_mutexattr_init(&attr); 58 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 59 | pthread_mutex_init(&_mutex, &attr); 60 | pthread_mutexattr_destroy(&attr); 61 | 62 | _objectInfosMap = [[NSMutableDictionary alloc] initWithCapacity:0]; 63 | _badgeQueue = dispatch_queue_create("com.badge.RJBadgeKit.queue", DISPATCH_QUEUE_CONCURRENT); 64 | 65 | [self setupRootBadge]; 66 | } 67 | return self; 68 | } 69 | 70 | - (void)dealloc { 71 | pthread_mutex_destroy(&_mutex); 72 | } 73 | 74 | #pragma mark - Observe 75 | 76 | - (void)observeWithInfo:(nullable RJBadgeInfo *)info 77 | { 78 | if (nil == info) return; 79 | 80 | pthread_mutex_lock(&_mutex); 81 | 82 | NSString *keyPath = info.keyPath; 83 | 84 | // get observation infos 85 | NSMutableSet *infos = [_objectInfosMap objectForKey:keyPath]; 86 | 87 | // lazilly create set of infos 88 | if (!infos) { 89 | infos = [NSMutableSet set]; 90 | [_objectInfosMap setObject:infos forKey:keyPath]; 91 | } 92 | 93 | // add info and oberve 94 | [infos addObject:info]; 95 | 96 | // unlock prior to callout 97 | pthread_mutex_unlock(&_mutex); 98 | 99 | // case where need to show badge while adding the observer 100 | id badge = [self badgeForKeyPath:keyPath]; 101 | if (badge && [badge needShow]) { 102 | [self statusChangeForBadges:@[badge]]; 103 | } 104 | } 105 | 106 | #pragma mark - Unobserve 107 | 108 | - (void)unobserveWithInfo:(nullable RJBadgeInfo *)info 109 | { 110 | if (nil == info) return; 111 | 112 | pthread_mutex_lock(&_mutex); 113 | 114 | NSString *keyPath = info.keyPath; 115 | 116 | // get observation infos 117 | NSMutableSet *infos = [_objectInfosMap objectForKey:keyPath]; 118 | 119 | // lookup registered info instance 120 | RJBadgeInfo *registeredInfo = [infos member:info]; 121 | id badgeView = registeredInfo.badgeView; 122 | 123 | if (nil != registeredInfo) { 124 | [infos removeObject:registeredInfo]; 125 | 126 | // remove no longer used infos 127 | if (0 == infos.count) { 128 | [_objectInfosMap removeObjectForKey:keyPath]; 129 | } 130 | } 131 | 132 | // unlock 133 | pthread_mutex_unlock(&_mutex); 134 | 135 | if (badgeView && [badgeView conformsToProtocol:@protocol(RJBadgeView)]) { 136 | dispatch_main_async_rjbk(^{ [badgeView hideBadge]; }); 137 | } 138 | } 139 | 140 | - (void)unobserveWithInfos:(nullable NSHashTable *)infos 141 | { 142 | if (0 == infos.count) return; 143 | 144 | for (RJBadgeInfo *info in infos) { 145 | [self unobserveWithInfo:info]; 146 | } 147 | } 148 | 149 | #pragma mark - Setup Badge 150 | - (void)setupRootBadge 151 | { 152 | NSString *badgeFile = [NSString badgeJSONPath]; 153 | NSDictionary *badgeFileDic = [NSDictionary dictionaryWithContentsOfFile:badgeFile]; 154 | NSDictionary *badgeDic = badgeFileDic ? : @{RJBadgeNameKey : @"root", 155 | RJBadgePathKey : @"root", 156 | RJBadgeCountKey: @(0), 157 | RJBadgeShowKey : @(YES)}; 158 | _root = [RJBadgeModel initWithDictionary:badgeDic]; 159 | 160 | if (!badgeFileDic) [self saveBadgeInfo]; 161 | } 162 | 163 | - (void)saveBadgeInfo { 164 | [[_root dictionaryFormat] writeToFile:[NSString badgeJSONPath] 165 | atomically:YES]; 166 | } 167 | 168 | #pragma mark - Set Badge 169 | - (void)setBadgeForKeyPath:(NSString *)keyPath { 170 | [self setBadgeForKeyPath:keyPath count:0]; 171 | } 172 | 173 | - (void)setBadgeForKeyPath:(NSString *)keyPath count:(NSUInteger)count 174 | { 175 | if (!keyPath) return; 176 | 177 | NSArray *keyPathArray = [keyPath componentsSeparatedByString:@"."]; 178 | NSMutableArray *notifyBadges = [NSMutableArray array]; 179 | 180 | pthread_mutex_lock(&_mutex); 181 | 182 | id bParent = _root; 183 | 184 | for (NSString *name in keyPathArray) { 185 | if ([name isEqualToString:@"root"]) continue; 186 | id objFind = nil; 187 | for (id obj in bParent.children) { 188 | if ([obj.name isEqualToString:name]) { 189 | objFind = obj; break; 190 | } 191 | } 192 | NSString *namePath = [NSString stringWithFormat:@".%@",name]; 193 | NSString *subKeyPath = [bParent.keyPath stringByAppendingString:namePath]; 194 | if (!objFind) { 195 | BOOL set = ([name isEqualToString:[keyPathArray lastObject]]); 196 | objFind = [RJBadgeModel initWithDictionary:@{RJBadgeNameKey : name, 197 | RJBadgePathKey : subKeyPath, 198 | RJBadgeCountKey: @(0), 199 | RJBadgeShowKey : @(set)}]; 200 | objFind.parent = bParent; 201 | [bParent addChild:objFind]; 202 | } 203 | bParent = objFind; 204 | if ([subKeyPath isEqualToString:keyPath]) { 205 | objFind.needShow = YES; 206 | objFind.count = count; 207 | } 208 | [notifyBadges addObject:objFind]; 209 | } 210 | [self saveBadgeInfo]; 211 | 212 | pthread_mutex_unlock(&_mutex); 213 | 214 | [self statusChangeForBadges:[notifyBadges mutableCopy]]; 215 | } 216 | 217 | #pragma mark - Clear Badge 218 | - (void)clearBadgeForKeyPath:(NSString *)keyPath { 219 | [self clearBadgeForKeyPath:keyPath forced:NO]; 220 | } 221 | 222 | - (void)clearBadgeForKeyPath:(NSString *)keyPath forced:(BOOL)forced 223 | { 224 | if (!keyPath) return; 225 | 226 | NSArray *keyPathArray = [keyPath componentsSeparatedByString:@"."]; 227 | NSMutableArray *notifyBadges = [NSMutableArray array]; 228 | 229 | pthread_mutex_lock(&_mutex); 230 | 231 | id bParent = _root; 232 | 233 | for (NSString *name in keyPathArray) { 234 | if ([name isEqualToString:@"root"]) continue; 235 | id objFind = nil; 236 | for (id obj in bParent.children) { 237 | if ([obj.name isEqualToString:name]) { 238 | objFind = obj; bParent = objFind; 239 | break; 240 | } 241 | } 242 | if (!objFind) { 243 | pthread_mutex_unlock(&_mutex); 244 | return; 245 | } 246 | if ([name isEqualToString:[keyPathArray lastObject]]) { 247 | objFind.needShow = NO; 248 | if ([objFind.children count] == 0 || forced) { 249 | if ([objFind.children count] && forced) { 250 | NSArray *bs = [objFind.allLinkChildren mutableCopy]; 251 | [notifyBadges addObjectsFromArray:bs]; 252 | [objFind clearAllChildren]; 253 | } 254 | objFind.count = 0; 255 | [objFind removeFromParent]; 256 | } 257 | [self saveBadgeInfo]; 258 | } 259 | [notifyBadges addObject:objFind]; 260 | } 261 | pthread_mutex_unlock(&_mutex); 262 | 263 | [self statusChangeForBadges:[notifyBadges mutableCopy]]; 264 | } 265 | 266 | #pragma mark - Status Change 267 | - (void)statusChangeForBadges:(NSArray> *)badges 268 | { 269 | if (![badges count]) return; 270 | 271 | for (id badge in badges) { 272 | NSString *path = badge.keyPath; 273 | 274 | if ([path isEqualToString:RJBadgeRootPath]) continue; 275 | 276 | pthread_mutex_lock(&_mutex); 277 | 278 | NSMutableSet *infos = [[_objectInfosMap objectForKey:path] copy]; 279 | 280 | pthread_mutex_unlock(&_mutex); 281 | 282 | [infos enumerateObjectsUsingBlock:^(RJBadgeInfo *bInfo, BOOL * _Nonnull stop) { 283 | id badgeView = bInfo.badgeView; 284 | if (badgeView && [badgeView conformsToProtocol:@protocol(RJBadgeView)]) { 285 | NSUInteger c = badge.count; 286 | dispatch_main_async_rjbk(^{ 287 | if (c > 0) { 288 | [badgeView showBadgeWithValue:c]; 289 | } else if (badge.needShow) { 290 | [badgeView showBadge]; 291 | } else { 292 | [badgeView hideBadge]; 293 | } 294 | }); 295 | } 296 | if (bInfo.block) { 297 | id observer = bInfo.controller.observer; 298 | bInfo.block(observer, @{ RJBadgePathKey : badge.keyPath, 299 | RJBadgeShowKey : @(badge.needShow), 300 | RJBadgeCountKey: @(badge.count) }); 301 | } 302 | }]; 303 | } 304 | } 305 | 306 | #pragma mark - Refresh Badge 307 | - (void)refreshBadgeWithInfos:(NSHashTable *)infos 308 | { 309 | if (0 == infos.count) return; 310 | 311 | for (RJBadgeInfo *bInfo in infos) { 312 | id badge = [self badgeForKeyPath:bInfo.keyPath]; 313 | id badgeView = bInfo.badgeView; 314 | if (badgeView && [badgeView conformsToProtocol:@protocol(RJBadgeView)]) { 315 | NSUInteger c = badge.count; 316 | dispatch_main_async_rjbk(^{ 317 | if (c > 0) { 318 | [badgeView showBadgeWithValue:c]; 319 | } else if (badge.needShow) { 320 | [badgeView showBadge]; 321 | } else { 322 | [badgeView hideBadge]; 323 | } 324 | }); 325 | } 326 | } 327 | } 328 | 329 | #pragma mark - Badge Status 330 | - (BOOL)statusForKeyPath:(NSString *)keyPath { 331 | return [[self badgeForKeyPath:keyPath] needShow]; 332 | } 333 | 334 | - (NSUInteger)countForKeyPath:(NSString *)keyPath 335 | { 336 | id badge = [self badgeForKeyPath:keyPath]; 337 | return badge ? badge.count : 0; 338 | } 339 | 340 | #pragma mark - Helper 341 | - (id)badgeForKeyPath:(NSString *)keyPath 342 | { 343 | NSArray *kPaths = [keyPath componentsSeparatedByString:@"."]; 344 | id badge = nil; 345 | 346 | pthread_mutex_lock(&_mutex); 347 | 348 | id bParent = _root; 349 | 350 | for (NSString *name in kPaths) { 351 | if ([name isEqualToString:RJBadgeRootPath]) { 352 | continue; 353 | } 354 | id objFind = nil; 355 | for (id obj in bParent.children) { 356 | if ([obj.name isEqualToString:name]) { 357 | objFind = obj; bParent = objFind; 358 | break; 359 | } 360 | } 361 | 362 | if (!objFind) { 363 | pthread_mutex_unlock(&_mutex); 364 | return nil; 365 | } 366 | 367 | badge = objFind; 368 | } 369 | 370 | pthread_mutex_unlock(&_mutex); 371 | 372 | return badge; 373 | } 374 | 375 | @end 376 | 377 | NS_ASSUME_NONNULL_END 378 | -------------------------------------------------------------------------------- /RJBadgeKit/Classes/BadgeModel/RJBadge.h: -------------------------------------------------------------------------------- 1 | // 2 | // RJBadge.h 3 | // RJBadgeKit 4 | // 5 | // Created by Ryan Jin on 04/08/2017. 6 | // 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @protocol RJBadge 14 | 15 | @required 16 | 17 | @property (strong, nonatomic, readonly) NSString *name; // e.g. 'badge' 18 | @property (strong, nonatomic, readonly) NSString *keyPath; // e.g. 'root.RJ.badge' 19 | /** 20 | 1. non-leaf node, sum of children 21 | 2. terminal node: return 'count' 22 | 3. setter valid for terminal node 23 | */ 24 | @property (assign, nonatomic) NSUInteger count; // badge value 25 | /** 26 | 1. non-leaf node: has any children? 27 | 2. terminal node: return 'needShow' 28 | */ 29 | @property (assign, nonatomic) BOOL needShow; // red dot 30 | 31 | // immediate children of current badge 32 | @property (strong, nonatomic, readonly) NSMutableArray> *children; 33 | // all linked children, including children's children 34 | @property (strong, nonatomic, readonly) NSMutableArray> *allLinkChildren; 35 | 36 | @property (weak, nonatomic) id parent; 37 | 38 | // regist nodes in terms of key path 39 | + (id)initWithDictionary:(NSDictionary *)dic; 40 | 41 | /** 42 | convert id object to dictionary, 43 | useful for, e.g. Data Persistence / Archive 44 | */ 45 | - (NSDictionary *)dictionaryFormat; 46 | 47 | - (void)addChild:(id)child; // add leaf 48 | - (void)removeChild:(id)child; // cut leaf 49 | - (void)clearAllChildren; // clearAll 50 | 51 | - (void)removeFromParent; // [parent removeChild:self] 52 | 53 | @end 54 | 55 | NS_ASSUME_NONNULL_END 56 | -------------------------------------------------------------------------------- /RJBadgeKit/Classes/BadgeModel/RJBadgeInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // RJBadgeInfo.h 3 | // RJBadgeKit 4 | // 5 | // Created by Ryan Jin on 06/12/2017. 6 | // 7 | 8 | #import 9 | #import "RJBadgeController.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface RJBadgeInfo : NSObject 14 | 15 | @property (nonatomic, copy, readonly) NSString *keyPath; 16 | @property (nonatomic, weak, readonly) RJBadgeController *controller; 17 | @property (nonatomic, copy, readonly) RJBadgeNotificationBlock block; 18 | 19 | @property (nonatomic, strong, readonly) id badgeView; 20 | 21 | - (instancetype)initWithController:(RJBadgeController *)controller keyPath:(NSString *)keyPath; 22 | 23 | - (instancetype)initWithController:(RJBadgeController *)controller keyPath:(NSString *)keyPath 24 | block:(nullable RJBadgeNotificationBlock)block; 25 | 26 | - (instancetype)initWithController:(RJBadgeController *)controller 27 | keyPath:(NSString *)keyPath 28 | badgeView:(nullable id)badgeView 29 | block:(nullable RJBadgeNotificationBlock)block; 30 | 31 | @end 32 | 33 | NS_ASSUME_NONNULL_END 34 | -------------------------------------------------------------------------------- /RJBadgeKit/Classes/BadgeModel/RJBadgeInfo.m: -------------------------------------------------------------------------------- 1 | // 2 | // RJBadgeInfo.m 3 | // RJBadgeKit 4 | // 5 | // Created by Ryan Jin on 06/12/2017. 6 | // 7 | 8 | #import "RJBadgeInfo.h" 9 | 10 | @interface RJBadgeInfo () 11 | 12 | @property (nonatomic, copy) NSString *keyPath; 13 | @property (nonatomic, weak) RJBadgeController *controller; 14 | @property (nonatomic, copy) RJBadgeNotificationBlock block; 15 | 16 | @property (nonatomic, strong) id badgeView; 17 | 18 | @end 19 | 20 | @implementation RJBadgeInfo { 21 | NSUInteger _badgeHash; 22 | } 23 | 24 | #pragma mark - Initialize 25 | 26 | - (instancetype)initWithController:(RJBadgeController *)controller 27 | keyPath:(NSString *)keyPath 28 | badgeView:(nullable id)badgeView 29 | block:(nullable RJBadgeNotificationBlock)block 30 | action:(nullable SEL)action 31 | { 32 | self = [super init]; 33 | if (self) { 34 | self.controller = controller; 35 | self.keyPath = keyPath; 36 | self.badgeView = badgeView; 37 | self.block = block; 38 | 39 | _badgeHash = self.keyPath.hash ^ self.controller.hash; 40 | } 41 | return self; 42 | } 43 | 44 | - (instancetype)initWithController:(RJBadgeController *)controller keyPath:(NSString *)keyPath { 45 | return [self initWithController:controller keyPath:keyPath badgeView:NULL block:NULL action:NULL]; 46 | } 47 | 48 | - (instancetype)initWithController:(RJBadgeController *)controller keyPath:(NSString *)keyPath 49 | block:(nullable RJBadgeNotificationBlock)block { 50 | return [self initWithController:controller keyPath:keyPath badgeView:NULL block:block action:NULL]; 51 | } 52 | 53 | - (instancetype)initWithController:(RJBadgeController *)controller 54 | keyPath:(NSString *)keyPath 55 | badgeView:(nullable id)badgeView 56 | block:(nullable RJBadgeNotificationBlock)block { 57 | return [self initWithController:controller keyPath:keyPath badgeView:badgeView block:block action:NULL]; 58 | } 59 | 60 | #pragma mark - Properties 61 | 62 | - (NSUInteger)hash { 63 | // hash must be consistent during the object's life time 64 | return _badgeHash/* [_keyPath hash] ^ [_controller hash] */; 65 | } 66 | 67 | - (BOOL)isEqual:(id)object 68 | { 69 | if (nil == object) { 70 | return NO; 71 | } 72 | if (self == object) { 73 | return YES; 74 | } 75 | if (![object isKindOfClass:[self class]]) { 76 | return NO; 77 | } 78 | RJBadgeInfo *badgeObj = (RJBadgeInfo *)object; 79 | BOOL isEqualPath = [_keyPath isEqualToString:badgeObj->_keyPath]; 80 | BOOL isEqualController = (_controller == badgeObj->_controller); 81 | 82 | return isEqualPath && isEqualController; 83 | } 84 | 85 | - (NSString *)debugDescription 86 | { 87 | NSMutableString *s = [NSMutableString stringWithFormat:@"<%@:%p keyPath:%@", 88 | NSStringFromClass([self class]), self, _keyPath]; 89 | if (NULL != _block) { 90 | [s appendFormat:@" block:%p", _block]; 91 | } 92 | 93 | [s appendString:@">"]; 94 | 95 | return s; 96 | } 97 | 98 | @end 99 | -------------------------------------------------------------------------------- /RJBadgeKit/Classes/BadgeModel/RJBadgeModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // RJBadgeModel.h 3 | // RJBadgeKit 4 | // 5 | // Created by Ryan Jin on 04/08/2017. 6 | // 7 | // 8 | 9 | #import 10 | #import "RJBadge.h" 11 | 12 | @interface RJBadgeModel : NSObject 13 | 14 | @property (strong, nonatomic, readonly) NSString *name; // e.g. 'badge' 15 | @property (strong, nonatomic, readonly) NSString *keyPath; // e.g. 'root.RJ.badge' 16 | /** 17 | 1. non-leaf node, sum of children 18 | 2. terminal node: return 'count' 19 | 3. setter valid for terminal node 20 | */ 21 | @property (assign, nonatomic) NSUInteger count; // badge value 22 | /** 23 | 1. non-leaf node: has any children? 24 | 2. terminal node: return 'needShow' 25 | */ 26 | @property (assign, nonatomic) BOOL needShow; // red dot 27 | 28 | // immediate children of current badge 29 | @property (strong, nonatomic, readonly) NSMutableArray> *children; 30 | // all linked children, including children's children 31 | @property (strong, nonatomic, readonly) NSMutableArray> *allLinkChildren; 32 | 33 | @property (weak, nonatomic) id parent; 34 | 35 | // regist nodes in terms of key path 36 | + (id)initWithDictionary:(NSDictionary *)dic; 37 | 38 | /** 39 | convert id object to dictionary, 40 | useful for, e.g. Data Persistence / Archive 41 | */ 42 | - (NSDictionary *)dictionaryFormat; 43 | 44 | - (void)addChild:(id)child; // add leaf 45 | - (void)removeChild:(id)child; // cut leaf 46 | - (void)clearAllChildren; // clearAll 47 | 48 | - (void)removeFromParent; // [parent removeChild:self] 49 | 50 | @end 51 | 52 | -------------------------------------------------------------------------------- /RJBadgeKit/Classes/BadgeModel/RJBadgeModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // RJBadgeModel.m 3 | // RJBadgeKit 4 | // 5 | // Created by Ryan Jin on 04/08/2017. 6 | // 7 | // 8 | 9 | #import "RJBadgeModel.h" 10 | #import 11 | 12 | NSString * const RJBadgeRootPath = @"root"; 13 | 14 | NSString * const RJBadgeNameKey = @"RJBadgeNameKey"; 15 | NSString * const RJBadgePathKey = @"RJBadgePathKey"; 16 | NSString * const RJBadgeChildrenKey = @"RJBadgeChildrenKey"; 17 | NSString * const RJBadgeShowKey = @"RJBadgeShowKey"; 18 | NSString * const RJBadgeCountKey = @"RJBadgeCountKey"; 19 | 20 | @interface RJBadgeModel () 21 | 22 | @property (strong, nonatomic, readwrite) NSString *name; 23 | @property (strong, nonatomic, readwrite) NSString *keyPath; 24 | 25 | @property (strong, nonatomic, readwrite) NSMutableArray> *children; 26 | 27 | @end 28 | 29 | @implementation RJBadgeModel { 30 | pthread_mutex_t _lock; 31 | } 32 | 33 | - (instancetype)initWithDictionary:(NSDictionary *)dic 34 | { 35 | self = [super init]; 36 | if (self) { 37 | self.name = dic[RJBadgeNameKey]; 38 | self.keyPath = dic[RJBadgePathKey]; 39 | 40 | self.needShow = [dic[RJBadgeShowKey] boolValue]; 41 | self.count = [dic[RJBadgeCountKey] unsignedIntegerValue]; 42 | self.children = [[NSMutableArray alloc] init]; 43 | 44 | NSArray *children = dic[RJBadgeChildrenKey]; 45 | if (children) { 46 | [children enumerateObjectsUsingBlock:^(NSDictionary *child, 47 | NSUInteger idx, 48 | BOOL *stop) { 49 | RJBadgeModel *obj = [RJBadgeModel initWithDictionary:child]; 50 | if (obj) {obj.parent = self; [self.children addObject:obj];} 51 | }]; 52 | } 53 | pthread_mutex_init(&_lock, NULL); 54 | } 55 | return self; 56 | } 57 | 58 | - (id)copyWithZone:(NSZone *)zone 59 | { 60 | RJBadgeModel *model = [[[self class] alloc] init]; 61 | 62 | model.name = self.name; 63 | model.keyPath = self.keyPath; 64 | model.count = self.count; 65 | model.needShow = self.needShow; 66 | model.parent = self.parent; 67 | model.children = [self.children mutableCopy]; 68 | 69 | return model; 70 | } 71 | 72 | - (void)dealloc { 73 | pthread_mutex_destroy(&_lock); 74 | } 75 | 76 | - (NSString *)debugDescription 77 | { 78 | NSMutableString *s = [NSMutableString stringWithFormat:@"<%@:%p keyPath:%@", NSStringFromClass([self class]), 79 | self, _keyPath]; 80 | [s appendFormat:@" count:%@", [@(_count) stringValue]]; 81 | [s appendFormat:@" needShow:%@", [@(_needShow) stringValue]]; 82 | 83 | if (NULL != _name) { 84 | [s appendFormat:@" name:%@", _name]; 85 | } 86 | if (NULL != _parent) { 87 | [s appendFormat:@" parent.path:%@", _parent.keyPath]; 88 | } 89 | if ([_children count]) { 90 | NSMutableArray *subPaths = [NSMutableArray array]; 91 | for (RJBadgeModel *child in _children) { 92 | [subPaths addObject:child.keyPath]; 93 | } 94 | [s appendFormat:@" children.path:%@", subPaths]; 95 | } 96 | [s appendString:@">"]; 97 | 98 | return s; 99 | } 100 | 101 | #pragma mark - RJBadge 102 | + (id)initWithDictionary:(NSDictionary *)dic 103 | { 104 | if (![dic count]) return nil; 105 | 106 | return [[RJBadgeModel alloc] initWithDictionary:dic]; 107 | } 108 | 109 | - (void)addChild:(id)child 110 | { 111 | pthread_mutex_lock(&_lock); 112 | 113 | if (child) [self.children addObject:child]; 114 | 115 | pthread_mutex_unlock(&_lock); 116 | } 117 | 118 | - (void)removeChild:(id)child 119 | { 120 | pthread_mutex_lock(&_lock); 121 | 122 | if ([self.children containsObject:child]) { 123 | [self.children removeObject:child]; 124 | if (![self.children count]) { 125 | self.needShow = NO; 126 | self.count = 0; 127 | } 128 | } 129 | 130 | pthread_mutex_unlock(&_lock); 131 | } 132 | 133 | - (void)clearAllChildren; 134 | { 135 | pthread_mutex_lock(&_lock); 136 | 137 | NSArray *children = [self.children copy]; 138 | 139 | [self.children removeAllObjects]; 140 | 141 | pthread_mutex_unlock(&_lock); 142 | 143 | for (id child in children) { 144 | child.needShow = NO; 145 | child.count = 0; 146 | [child clearAllChildren]; 147 | } 148 | } 149 | 150 | - (void)removeFromParent 151 | { 152 | if (self.parent) { 153 | [self.parent removeChild:self]; 154 | self.parent = nil; 155 | } 156 | } 157 | 158 | - (NSDictionary *)dictionaryFormat 159 | { 160 | NSMutableDictionary *dic = [NSMutableDictionary new]; 161 | 162 | if (self.name) dic[RJBadgeNameKey] = self.name; 163 | if (self.keyPath) dic[RJBadgePathKey] = self.keyPath; 164 | if (self.count) dic[RJBadgeCountKey] = @(self.count); 165 | if (self.needShow) dic[RJBadgeShowKey] = @(self.needShow); 166 | 167 | if ([self.children count]) { 168 | NSMutableArray *children = [NSMutableArray new]; 169 | dic[RJBadgeChildrenKey] = children; 170 | [self.children enumerateObjectsUsingBlock:^(id obj, 171 | NSUInteger idx, 172 | BOOL *stop) { 173 | [children addObject:[obj dictionaryFormat]]; 174 | }]; 175 | } 176 | return dic; 177 | } 178 | 179 | #pragma mark - setter/getter 180 | - (BOOL)needShow 181 | { 182 | if ([self.children count]) { 183 | for (id badge in self.children) { 184 | if (badge.needShow) return YES; 185 | } 186 | return NO; 187 | } 188 | return _needShow; 189 | } 190 | 191 | - (NSUInteger)count 192 | { 193 | if ([self.children count]) { 194 | __block NSUInteger subCount = 0; 195 | [self.children enumerateObjectsUsingBlock:^(id obj, 196 | NSUInteger idx, 197 | BOOL *stop) { 198 | subCount += obj.count; 199 | }]; 200 | _count = subCount; 201 | } 202 | return _count; 203 | } 204 | 205 | - (NSMutableArray> *)allLinkChildren 206 | { 207 | NSMutableArray *links = [self.children mutableCopy]; 208 | 209 | if ([self.children count]) { 210 | [self.children enumerateObjectsUsingBlock:^(id obj, 211 | NSUInteger idx, 212 | BOOL *stop) { 213 | [links addObjectsFromArray:obj.allLinkChildren]; 214 | }]; 215 | } 216 | return links; 217 | } 218 | 219 | @end 220 | -------------------------------------------------------------------------------- /RJBadgeKit/Classes/BadgeView/RJBadgeView.h: -------------------------------------------------------------------------------- 1 | // 2 | // RJBadgeView.h 3 | // RJBadgeKit 4 | // 5 | // Created by Ryan Jin on 04/08/2017. 6 | // 7 | // 8 | 9 | #import 10 | 11 | /** 12 | priority: number > custom view > red dot 13 | */ 14 | 15 | @protocol RJBadgeView 16 | 17 | @required 18 | 19 | @property (nonatomic, strong) UILabel *badge; 20 | @property (nonatomic, strong) UIFont *badgeFont; // default bold size 9 21 | @property (nonatomic, strong) UIColor *badgeTextColor; // default white color 22 | @property (nonatomic, strong) UIColor *badgeBgColor; 23 | @property (nonatomic, assign) CGFloat badgeRadius; // for red dot mode 24 | @property (nonatomic, assign) CGPoint badgeOffset; // offset from right-top 25 | 26 | - (void)showBadge; // badge with red dot 27 | - (void)hideBadge; 28 | 29 | // badge with number, pass zero to hide badge 30 | - (void)showBadgeWithValue:(NSUInteger)value; 31 | 32 | @optional 33 | 34 | @property (nonatomic, strong) UIView *badgeCustomView; 35 | /** 36 | convenient interface: 37 | create 'cusomView' (UIImageView) using badgeImage 38 | view's size would simply be set as half of image. 39 | */ 40 | @property (nonatomic, strong) UIImage *badgeImage; 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /RJBadgeKit/Classes/BadgeView/UIBarButtonItem+RJBadge.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIBarButtonItem+RJBadge.h 3 | // RJBadgeKit 4 | // 5 | // Created by Ryan Jin on 04/08/2017. 6 | // 7 | // 8 | 9 | #import 10 | #import "RJBadgeView.h" 11 | 12 | @interface UIBarButtonItem (RJBadge) 13 | 14 | - (void)showBadge; // badge with red dot 15 | - (void)hideBadge; 16 | 17 | // badge with number, pass zero to hide badge 18 | - (void)showBadgeWithValue:(NSUInteger)value; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /RJBadgeKit/Classes/BadgeView/UIBarButtonItem+RJBadge.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIBarButtonItem+RJBadge.m 3 | // RJBadgeKit 4 | // 5 | // Created by Ryan Jin on 04/08/2017. 6 | // 7 | // 8 | 9 | #import "UIBarButtonItem+RJBadge.h" 10 | #import 11 | #import "UIView+RJBadge.h" 12 | 13 | @implementation UIBarButtonItem (RJBadge) 14 | 15 | #pragma mark - RJBadgeView 16 | - (void)showBadge { 17 | [[self badgeView] showBadge]; 18 | } 19 | - (void)hideBadge { 20 | [[self badgeView] hideBadge]; 21 | } 22 | 23 | - (void)showBadgeWithValue:(NSUInteger)value { 24 | [[self badgeView] showBadgeWithValue:value]; 25 | } 26 | 27 | #pragma mark - private method 28 | - (UIView *)badgeView { 29 | return [self valueForKeyPath:@"_view"]; 30 | } 31 | 32 | #pragma mark - setter/getter 33 | - (UILabel *)badge { 34 | return [self badgeView].badge; 35 | } 36 | 37 | - (void)setBadge:(UILabel *)label { 38 | [[self badgeView] setBadge:label]; 39 | } 40 | 41 | - (UIFont *)badgeFont { 42 | return [self badgeView].badgeFont; 43 | } 44 | 45 | - (void)setBadgeFont:(UIFont *)badgeFont { 46 | [[self badgeView] setBadgeFont:badgeFont]; 47 | } 48 | 49 | - (UIColor *)badgeTextColor { 50 | return [[self badgeView] badgeTextColor]; 51 | } 52 | 53 | - (void)setBadgeTextColor:(UIColor *)badgeTextColor { 54 | [[self badgeView] setBadgeTextColor:badgeTextColor]; 55 | } 56 | 57 | - (CGFloat)badgeRadius { 58 | return [[self badgeView] badgeRadius]; 59 | } 60 | 61 | - (void)setBadgeRadius:(CGFloat)badgeRadius { 62 | [[self badgeView] setBadgeRadius:badgeRadius]; 63 | } 64 | 65 | - (CGPoint)badgeOffset { 66 | return [[self badgeView] badgeOffset]; 67 | } 68 | 69 | - (void)setBadgeOffset:(CGPoint)badgeOffset { 70 | [[self badgeView] setBadgeOffset:badgeOffset]; 71 | } 72 | 73 | - (UIColor *)badgeBgColor { 74 | return [[self badgeView] badgeBgColor]; 75 | } 76 | 77 | - (void)setBadgeBgColor:(UIColor *)badgeBgColor { 78 | [[self badgeView] setBadgeBgColor:badgeBgColor]; 79 | } 80 | 81 | @end 82 | -------------------------------------------------------------------------------- /RJBadgeKit/Classes/BadgeView/UITabBarItem+RJBadge.h: -------------------------------------------------------------------------------- 1 | // 2 | // UITabBarItem+RJBadge.h 3 | // RJBadgeKit 4 | // 5 | // Created by Ryan Jin on 04/08/2017. 6 | // 7 | // 8 | 9 | #import 10 | #import "RJBadgeView.h" 11 | 12 | @interface UITabBarItem (RJBadge) 13 | 14 | - (void)showBadge; // badge with red dot 15 | - (void)hideBadge; 16 | 17 | // badge with number, pass zero to hide badge 18 | - (void)showBadgeWithValue:(NSUInteger)value; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /RJBadgeKit/Classes/BadgeView/UITabBarItem+RJBadge.m: -------------------------------------------------------------------------------- 1 | // 2 | // UITabBarItem+RJBadge.m 3 | // RJBadgeKit 4 | // 5 | // Created by Ryan Jin on 04/08/2017. 6 | // 7 | // 8 | 9 | #import "UITabBarItem+RJBadge.h" 10 | #import 11 | #import "UIView+RJBadge.h" 12 | 13 | @implementation UITabBarItem (RJBadge) 14 | 15 | #pragma mark - RJBadgeView 16 | - (void)showBadge { 17 | [[self badgeView] showBadge]; 18 | } 19 | - (void)hideBadge { 20 | [[self badgeView] hideBadge]; 21 | } 22 | 23 | - (void)showBadgeWithValue:(NSUInteger)value { 24 | [[self badgeView] showBadgeWithValue:value]; 25 | } 26 | 27 | #pragma mark - private method 28 | - (UIView *)badgeView 29 | { 30 | UIView *bottomView = [self valueForKeyPath:@"_view"]; // UITabbarButtion 31 | UIView *parentView = nil; // UIImageView 32 | if (bottomView) { 33 | parentView = [self find:bottomView 34 | firstSubviewWithClass:NSClassFromString(@"UITabBarSwappableImageView")]; 35 | } 36 | return parentView; 37 | } 38 | 39 | - (UIView *)find:(UIView *)view firstSubviewWithClass:(Class)cls 40 | { 41 | __block UIView *targetView = nil; 42 | [view.subviews enumerateObjectsUsingBlock:^(UIView *subview, 43 | NSUInteger idx, 44 | BOOL *stop) { 45 | if ([subview isKindOfClass:cls]) { 46 | targetView = subview; *stop = YES; 47 | } 48 | }]; 49 | return targetView; 50 | } 51 | 52 | #pragma mark - setter/getter 53 | - (UILabel *)badge { 54 | return [self badgeView].badge; 55 | } 56 | 57 | - (void)setBadge:(UILabel *)label { 58 | [[self badgeView] setBadge:label]; 59 | } 60 | 61 | - (UIFont *)badgeFont { 62 | return [self badgeView].badgeFont; 63 | } 64 | 65 | - (void)setBadgeFont:(UIFont *)badgeFont { 66 | [[self badgeView] setBadgeFont:badgeFont]; 67 | } 68 | 69 | - (UIColor *)badgeTextColor { 70 | return [[self badgeView] badgeTextColor]; 71 | } 72 | 73 | - (void)setBadgeTextColor:(UIColor *)badgeTextColor { 74 | [[self badgeView] setBadgeTextColor:badgeTextColor]; 75 | } 76 | 77 | - (CGFloat)badgeRadius { 78 | return [[self badgeView] badgeRadius]; 79 | } 80 | 81 | - (void)setBadgeRadius:(CGFloat)badgeRadius { 82 | [[self badgeView] setBadgeRadius:badgeRadius]; 83 | } 84 | 85 | - (CGPoint)badgeOffset { 86 | return [[self badgeView] badgeOffset]; 87 | } 88 | 89 | - (void)setBadgeOffset:(CGPoint)badgeOffset { 90 | [[self badgeView] setBadgeOffset:badgeOffset]; 91 | } 92 | 93 | - (UIColor *)badgeBgColor { 94 | return [[self badgeView] badgeBgColor]; 95 | } 96 | 97 | - (void)setBadgeBgColor:(UIColor *)badgeBgColor { 98 | [[self badgeView] setBadgeBgColor:badgeBgColor]; 99 | } 100 | 101 | @end 102 | -------------------------------------------------------------------------------- /RJBadgeKit/Classes/BadgeView/UIView+RJBadge.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+RJBadge.h 3 | // RJBadgeKit 4 | // 5 | // Created by Ryan Jin on 04/08/2017. 6 | // 7 | // 8 | 9 | #import 10 | #import "RJBadgeView.h" 11 | 12 | @interface UIView (RJBadge) 13 | 14 | - (void)showBadge; // badge with red dot 15 | - (void)hideBadge; 16 | 17 | // badge with number, pass zero to hide badge 18 | - (void)showBadgeWithValue:(NSUInteger)value; 19 | 20 | @end 21 | 22 | -------------------------------------------------------------------------------- /RJBadgeKit/Classes/BadgeView/UIView+RJBadge.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+RJBadge.m 3 | // RJBadgeKit 4 | // 5 | // Created by Ryan Jin on 04/08/2017. 6 | // 7 | // 8 | 9 | #import "UIView+RJBadge.h" 10 | #import 11 | 12 | #define kRJBadgeDefaultFont ([UIFont boldSystemFontOfSize:9]) 13 | #define kRJBadgeDefaultMaximumBadgeNumber 99 14 | 15 | static const CGFloat kRJBadgeDefaultRadius = 3.f; 16 | 17 | @implementation UIView (RJBadge) 18 | 19 | #pragma mark - RJBadgeView 20 | - (void)showBadge 21 | { 22 | CGFloat offsetX = CGRectGetWidth(self.frame) + 2 + self.badgeOffset.x; 23 | CGPoint center = CGPointMake(offsetX, self.badgeOffset.y); 24 | 25 | if (self.badgeCustomView) { 26 | self.badgeCustomView.hidden = NO; 27 | self.badge.hidden = YES; 28 | self.badgeCustomView.center = center; 29 | } else { 30 | CGFloat w = (self.badgeRadius ? : kRJBadgeDefaultRadius) * 2; 31 | CGRect r = CGRectMake(CGRectGetWidth(self.frame), -w, w, w); 32 | 33 | self.badge.frame = r; 34 | self.badge.text = @""; 35 | self.badge.hidden = NO; 36 | self.badge.layer.cornerRadius = w / 2; 37 | self.badge.center = center; 38 | } 39 | } 40 | 41 | - (void)showBadgeWithValue:(NSUInteger)value 42 | { 43 | self.badgeCustomView.hidden = YES; 44 | 45 | self.badge.hidden = (value == 0); 46 | self.badge.font = self.badgeFont; 47 | self.badge.text = (value > kRJBadgeDefaultMaximumBadgeNumber ? 48 | [NSString stringWithFormat:@"%@+", @(kRJBadgeDefaultMaximumBadgeNumber)] : 49 | [NSString stringWithFormat:@"%@" , @(value)]); 50 | [self adjustLabelWidth:self.badge]; 51 | 52 | CGRect frame = self.badge.frame; 53 | frame.size.width += 4; 54 | frame.size.height += 4; 55 | 56 | if(CGRectGetWidth(frame) < CGRectGetHeight(frame)) { 57 | frame.size.width = CGRectGetHeight(frame); 58 | } 59 | self.badge.frame = frame; 60 | CGFloat offsetX = CGRectGetWidth(self.frame) + 2 + self.badgeOffset.x; 61 | self.badge.center = CGPointMake(offsetX, self.badgeOffset.y); 62 | 63 | self.badge.layer.cornerRadius = CGRectGetHeight(self.badge.frame) / 2.f; 64 | } 65 | 66 | - (void)hideBadge 67 | { 68 | if (self.badgeCustomView) { 69 | self.badgeCustomView.hidden = YES; 70 | } 71 | self.badge.hidden = YES; 72 | } 73 | 74 | #pragma mark - private methods 75 | - (void)adjustLabelWidth:(UILabel *)label 76 | { 77 | [label setNumberOfLines:0]; 78 | 79 | NSString *s = label.text; 80 | UIFont *font = [label font]; 81 | CGSize size = CGSizeMake(320,2000); 82 | 83 | CGSize labelsize = CGSizeZero; 84 | 85 | if (![s respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]) { 86 | #pragma clang diagnostic push 87 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 88 | labelsize = [s sizeWithFont:font 89 | constrainedToSize:size 90 | lineBreakMode:NSLineBreakByWordWrapping]; 91 | #pragma clang diagnostic pop 92 | } else { 93 | NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; 94 | [style setLineBreakMode:NSLineBreakByWordWrapping]; 95 | 96 | labelsize = [s boundingRectWithSize:size 97 | options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) 98 | attributes:@{NSFontAttributeName: font, NSParagraphStyleAttributeName: style} 99 | context:nil].size; 100 | } 101 | CGRect frame = label.frame; 102 | frame.size = CGSizeMake(ceilf(labelsize.width), ceilf(labelsize.height)); 103 | [label setFrame:frame]; 104 | } 105 | 106 | #pragma mark - setter/getter 107 | - (UILabel *)badge 108 | { 109 | UILabel *bLabel = objc_getAssociatedObject(self, _cmd); 110 | if (!bLabel) { 111 | CGFloat width = kRJBadgeDefaultRadius * 2; 112 | CGRect rect = CGRectMake(CGRectGetWidth(self.frame), -width, width, width); 113 | bLabel = [[UILabel alloc] initWithFrame:rect]; 114 | bLabel.textAlignment = NSTextAlignmentCenter; 115 | bLabel.backgroundColor = [UIColor colorWithRed: 1.f 116 | green: 93.f/225.f 117 | blue:165.f/255.f 118 | alpha:1.f]; 119 | bLabel.textColor = [UIColor whiteColor]; 120 | bLabel.text = @""; 121 | // CGFloat offsetX = CGRectGetWidth(self.frame) + 2 + self.badgeOffset.x; 122 | // bLabel.center = CGPointMake(offsetX, self.badgeOffset.y); 123 | 124 | bLabel.layer.cornerRadius = kRJBadgeDefaultRadius; 125 | bLabel.layer.masksToBounds = YES; 126 | bLabel.hidden = YES; 127 | 128 | objc_setAssociatedObject(self, 129 | _cmd, 130 | bLabel, 131 | OBJC_ASSOCIATION_RETAIN_NONATOMIC); 132 | [self addSubview:bLabel]; 133 | [self bringSubviewToFront:bLabel]; 134 | } 135 | return bLabel; 136 | } 137 | 138 | - (void)setBadge:(UILabel *)badge { 139 | objc_setAssociatedObject(self, 140 | @selector(badge), 141 | badge, 142 | OBJC_ASSOCIATION_RETAIN); 143 | } 144 | 145 | - (UIFont *)badgeFont { 146 | return objc_getAssociatedObject(self, _cmd) ?: kRJBadgeDefaultFont; 147 | } 148 | 149 | - (void)setBadgeFont:(UIFont *)badgeFont 150 | { 151 | objc_setAssociatedObject(self, 152 | @selector(badgeFont), 153 | badgeFont, 154 | OBJC_ASSOCIATION_RETAIN); 155 | self.badge.font = badgeFont; 156 | } 157 | 158 | - (UIColor *)badgeBgColor { 159 | return objc_getAssociatedObject(self, _cmd); 160 | } 161 | 162 | - (void)setBadgeBgColor:(UIColor *)badgeBgColor 163 | { 164 | objc_setAssociatedObject(self, 165 | @selector(badgeBgColor), 166 | badgeBgColor, 167 | OBJC_ASSOCIATION_RETAIN); 168 | self.badge.backgroundColor = badgeBgColor; 169 | } 170 | 171 | - (UIColor *)badgeTextColor { 172 | return objc_getAssociatedObject(self, _cmd); 173 | } 174 | 175 | - (void)setBadgeTextColor:(UIColor *)badgeTextColor 176 | { 177 | objc_setAssociatedObject(self, 178 | @selector(badgeTextColor), 179 | badgeTextColor, 180 | OBJC_ASSOCIATION_RETAIN); 181 | self.badge.textColor = badgeTextColor; 182 | } 183 | 184 | - (CGFloat)badgeRadius { 185 | return [objc_getAssociatedObject(self, _cmd) floatValue]; 186 | } 187 | 188 | - (void)setBadgeRadius:(CGFloat)badgeRadius { 189 | objc_setAssociatedObject(self, 190 | @selector(badgeRadius), 191 | @(badgeRadius), 192 | OBJC_ASSOCIATION_RETAIN); 193 | } 194 | 195 | - (CGPoint)badgeOffset 196 | { 197 | NSValue *offset = objc_getAssociatedObject(self, _cmd); 198 | 199 | if (!offset) return CGPointZero; 200 | 201 | return [offset CGPointValue]; 202 | } 203 | 204 | - (void)setBadgeOffset:(CGPoint)badgeOffset { 205 | objc_setAssociatedObject(self, 206 | @selector(badgeOffset), 207 | [NSValue valueWithCGPoint:badgeOffset], 208 | OBJC_ASSOCIATION_RETAIN_NONATOMIC); 209 | } 210 | 211 | - (UIImage *)badgeImage { 212 | return objc_getAssociatedObject(self, _cmd); 213 | } 214 | 215 | - (void)setBadgeImage:(UIImage *)badgeImage 216 | { 217 | if (!badgeImage) { 218 | [self.badgeCustomView removeFromSuperview]; 219 | [self setBadgeCustomView:nil]; 220 | } else { 221 | self.badgeCustomView = [[UIImageView alloc] initWithImage:badgeImage]; 222 | objc_setAssociatedObject(self, 223 | @selector(badgeImage), 224 | badgeImage, 225 | OBJC_ASSOCIATION_RETAIN); 226 | } 227 | } 228 | 229 | - (UIView *)badgeCustomView { 230 | return objc_getAssociatedObject(self, _cmd); 231 | } 232 | 233 | - (void)setBadgeCustomView:(UIView *)badgeCustomView 234 | { 235 | if (self.badgeCustomView == badgeCustomView) return; 236 | 237 | if (self.badgeCustomView) [self.badgeCustomView removeFromSuperview]; 238 | if (badgeCustomView) [self addSubview:badgeCustomView]; 239 | 240 | objc_setAssociatedObject(self, 241 | @selector(badgeCustomView), 242 | badgeCustomView, 243 | OBJC_ASSOCIATION_RETAIN_NONATOMIC); 244 | if (self.badgeCustomView) { 245 | CGRect bound = badgeCustomView.bounds; 246 | bound.origin.x = CGRectGetWidth(self.frame); 247 | bound.origin.y = -bound.size.height; 248 | 249 | self.badgeCustomView.frame = bound; 250 | self.badgeCustomView.hidden = YES; 251 | // CGFloat offsetX = CGRectGetWidth(self.frame) + 2 + self.badgeOffset.x; 252 | // self.badgeCustomView.center = CGPointMake(offsetX, self.badgeOffset.y); 253 | } 254 | // [self showBadge]; // refresh - in case of setting custom view after show badge 255 | } 256 | 257 | @end 258 | -------------------------------------------------------------------------------- /RJBadgeKit/Classes/Helper/NSString+RJBadge.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+RJBadge.h 3 | // RJBadgeKit 4 | // 5 | // Created by Ryan Jin on 06/08/2017. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @interface NSString (RJBadge) 12 | 13 | + (NSString *)badgeFilePath; 14 | + (NSString *)badgeJSONPath; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /RJBadgeKit/Classes/Helper/NSString+RJBadge.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+RJBadge.m 3 | // RJBadgeKit 4 | // 5 | // Created by Ryan Jin on 06/08/2017. 6 | // 7 | // 8 | 9 | #import "NSString+RJBadge.h" 10 | 11 | @implementation NSString (RJBadge) 12 | 13 | #pragma mark - public 14 | + (NSString *)badgeFilePath 15 | { 16 | NSString *mpath = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Application Support"]; 17 | NSString *bpath = [mpath stringByAppendingPathComponent:@"RJBadge"]; 18 | 19 | NSURL *url = [NSURL fileURLWithPath:bpath]; 20 | [self addSkipBackupAttributeToItemAtURL:url]; 21 | 22 | return bpath; 23 | } 24 | 25 | + (NSString *)badgeJSONPath 26 | { 27 | NSFileManager *fileManager = [NSFileManager defaultManager]; 28 | NSString *filePath = [self badgeFilePath]; 29 | 30 | if (![fileManager fileExistsAtPath:filePath]) { 31 | [fileManager createDirectoryAtPath:filePath 32 | withIntermediateDirectories:YES 33 | attributes:nil error:nil]; 34 | } 35 | return [filePath stringByAppendingPathComponent:@"badge.json"]; 36 | } 37 | 38 | #pragma mark - private method 39 | + (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL 40 | { 41 | if ([[NSFileManager defaultManager] fileExistsAtPath:[URL path]]) { 42 | NSError *error = nil; 43 | BOOL success = [URL setResourceValue:[NSNumber numberWithBool:YES] 44 | forKey:NSURLIsExcludedFromBackupKey 45 | error:&error]; 46 | if (!success) { 47 | NSLog(@"Error excluding %@ from backup %@", [URL lastPathComponent], 48 | error); 49 | } 50 | return success; 51 | } 52 | return NO; 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /RJBadgeKit/Classes/RJBadgeKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // RJBadgeKit.h 3 | // RJBadgeKit 4 | // 5 | // Created by Ryan Jin on 04/08/2017. 6 | // 7 | // 8 | 9 | #ifndef RJBadgeKit_h 10 | #define RJBadgeKit_h 11 | 12 | #import "RJBadgeController.h" 13 | #import "NSObject+RJBadgeController.h" 14 | #import "UIBarButtonItem+RJBadge.h" 15 | #import "UITabBarItem+RJBadge.h" 16 | #import "UIView+RJBadge.h" 17 | 18 | #endif /* RJBadgeKit_h */ 19 | -------------------------------------------------------------------------------- /_Pods.xcodeproj: -------------------------------------------------------------------------------- 1 | Example/Pods/Pods.xcodeproj --------------------------------------------------------------------------------