From 54978347b1f27b59bde2e6551a65b9ca00b1e52b Mon Sep 17 00:00:00 2001 From: wustzhy Date: Tue, 3 Jan 2017 14:24:37 +0800 Subject: [PATCH] 2nd push add project --runLoopDemo --- RunLoopDemo.xcodeproj/project.pbxproj | 454 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + RunLoopDemo/Base.lproj/LaunchScreen.xib | 41 ++ RunLoopDemo/CCAppDelegate.h | 26 + RunLoopDemo/CCAppDelegate.m | 93 ++++ .../CCRunLoopCustomInputSourceThread.h | 13 + .../CCRunLoopCustomInputSourceThread.m | 61 +++ RunLoopDemo/CCRunLoopInputSource.h | 46 ++ RunLoopDemo/CCRunLoopInputSource.m | 129 +++++ RunLoopDemo/CCRunLoopThread.h | 13 + RunLoopDemo/CCRunLoopThread.m | 107 +++++ RunLoopDemo/CCTestRunLoopViewController.h | 18 + RunLoopDemo/CCTestRunLoopViewController.m | 186 +++++++ .../AppIcon.appiconset/Contents.json | 38 ++ RunLoopDemo/Info.plist | 36 ++ RunLoopDemo/TestTableViewController.h | 13 + RunLoopDemo/TestTableViewController.m | 133 +++++ RunLoopDemo/main.m | 16 + RunLoopDemoTests/Info.plist | 24 + RunLoopDemoTests/RunLoopDemoTests.m | 40 ++ t1.txt | 7 + 21 files changed, 1501 insertions(+) create mode 100755 RunLoopDemo.xcodeproj/project.pbxproj create mode 100755 RunLoopDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100755 RunLoopDemo/Base.lproj/LaunchScreen.xib create mode 100755 RunLoopDemo/CCAppDelegate.h create mode 100755 RunLoopDemo/CCAppDelegate.m create mode 100755 RunLoopDemo/CCRunLoopCustomInputSourceThread.h create mode 100755 RunLoopDemo/CCRunLoopCustomInputSourceThread.m create mode 100755 RunLoopDemo/CCRunLoopInputSource.h create mode 100755 RunLoopDemo/CCRunLoopInputSource.m create mode 100755 RunLoopDemo/CCRunLoopThread.h create mode 100755 RunLoopDemo/CCRunLoopThread.m create mode 100755 RunLoopDemo/CCTestRunLoopViewController.h create mode 100755 RunLoopDemo/CCTestRunLoopViewController.m create mode 100755 RunLoopDemo/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100755 RunLoopDemo/Info.plist create mode 100644 RunLoopDemo/TestTableViewController.h create mode 100644 RunLoopDemo/TestTableViewController.m create mode 100755 RunLoopDemo/main.m create mode 100755 RunLoopDemoTests/Info.plist create mode 100755 RunLoopDemoTests/RunLoopDemoTests.m diff --git a/RunLoopDemo.xcodeproj/project.pbxproj b/RunLoopDemo.xcodeproj/project.pbxproj new file mode 100755 index 0000000..6058a9e --- /dev/null +++ b/RunLoopDemo.xcodeproj/project.pbxproj @@ -0,0 +1,454 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 0C648F7C1E1B5F580019AD64 /* TestTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C648F7B1E1B5F580019AD64 /* TestTableViewController.m */; }; + 34879B8719F4D0E100E961F2 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 34879B8619F4D0E100E961F2 /* main.m */; }; + 34879B9219F4D0E100E961F2 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 34879B9119F4D0E100E961F2 /* Images.xcassets */; }; + 34879B9519F4D0E100E961F2 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 34879B9319F4D0E100E961F2 /* LaunchScreen.xib */; }; + 34879BA119F4D0E100E961F2 /* RunLoopDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 34879BA019F4D0E100E961F2 /* RunLoopDemoTests.m */; }; + 34879BBC19F50ADA00E961F2 /* CCRunLoopInputSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 34879BB919F50ADA00E961F2 /* CCRunLoopInputSource.m */; }; + 34879BBD19F50ADA00E961F2 /* CCRunLoopCustomInputSourceThread.m in Sources */ = {isa = PBXBuildFile; fileRef = 34879BBB19F50ADA00E961F2 /* CCRunLoopCustomInputSourceThread.m */; }; + 34879BC419F50B0300E961F2 /* CCAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 34879BBF19F50B0300E961F2 /* CCAppDelegate.m */; }; + 34879BC519F50B0300E961F2 /* CCTestRunLoopViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34879BC119F50B0300E961F2 /* CCTestRunLoopViewController.m */; }; + 34879BC619F50B0300E961F2 /* CCRunLoopThread.m in Sources */ = {isa = PBXBuildFile; fileRef = 34879BC319F50B0300E961F2 /* CCRunLoopThread.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 34879B9B19F4D0E100E961F2 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 34879B7919F4D0E100E961F2 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 34879B8019F4D0E100E961F2; + remoteInfo = RunLoopDemo; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 0C648F7A1E1B5F570019AD64 /* TestTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestTableViewController.h; sourceTree = ""; }; + 0C648F7B1E1B5F580019AD64 /* TestTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TestTableViewController.m; sourceTree = ""; }; + 34879B8119F4D0E100E961F2 /* RunLoopDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RunLoopDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 34879B8519F4D0E100E961F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 34879B8619F4D0E100E961F2 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 34879B9119F4D0E100E961F2 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 34879B9419F4D0E100E961F2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; + 34879B9A19F4D0E100E961F2 /* RunLoopDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunLoopDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 34879B9F19F4D0E100E961F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 34879BA019F4D0E100E961F2 /* RunLoopDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RunLoopDemoTests.m; sourceTree = ""; }; + 34879BB819F50ADA00E961F2 /* CCRunLoopInputSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCRunLoopInputSource.h; sourceTree = ""; }; + 34879BB919F50ADA00E961F2 /* CCRunLoopInputSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCRunLoopInputSource.m; sourceTree = ""; }; + 34879BBA19F50ADA00E961F2 /* CCRunLoopCustomInputSourceThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCRunLoopCustomInputSourceThread.h; sourceTree = ""; }; + 34879BBB19F50ADA00E961F2 /* CCRunLoopCustomInputSourceThread.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCRunLoopCustomInputSourceThread.m; sourceTree = ""; }; + 34879BBE19F50B0300E961F2 /* CCAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCAppDelegate.h; sourceTree = ""; }; + 34879BBF19F50B0300E961F2 /* CCAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCAppDelegate.m; sourceTree = ""; }; + 34879BC019F50B0300E961F2 /* CCTestRunLoopViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCTestRunLoopViewController.h; sourceTree = ""; }; + 34879BC119F50B0300E961F2 /* CCTestRunLoopViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCTestRunLoopViewController.m; sourceTree = ""; }; + 34879BC219F50B0300E961F2 /* CCRunLoopThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCRunLoopThread.h; sourceTree = ""; }; + 34879BC319F50B0300E961F2 /* CCRunLoopThread.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCRunLoopThread.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 34879B7E19F4D0E100E961F2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 34879B9719F4D0E100E961F2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 34879B7819F4D0E100E961F2 = { + isa = PBXGroup; + children = ( + 34879B8319F4D0E100E961F2 /* RunLoopDemo */, + 34879B9D19F4D0E100E961F2 /* RunLoopDemoTests */, + 34879B8219F4D0E100E961F2 /* Products */, + ); + sourceTree = ""; + }; + 34879B8219F4D0E100E961F2 /* Products */ = { + isa = PBXGroup; + children = ( + 34879B8119F4D0E100E961F2 /* RunLoopDemo.app */, + 34879B9A19F4D0E100E961F2 /* RunLoopDemoTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 34879B8319F4D0E100E961F2 /* RunLoopDemo */ = { + isa = PBXGroup; + children = ( + 34879BBE19F50B0300E961F2 /* CCAppDelegate.h */, + 34879BBF19F50B0300E961F2 /* CCAppDelegate.m */, + 34879BC019F50B0300E961F2 /* CCTestRunLoopViewController.h */, + 34879BC119F50B0300E961F2 /* CCTestRunLoopViewController.m */, + 0C648F7A1E1B5F570019AD64 /* TestTableViewController.h */, + 0C648F7B1E1B5F580019AD64 /* TestTableViewController.m */, + 34879BC219F50B0300E961F2 /* CCRunLoopThread.h */, + 34879BC319F50B0300E961F2 /* CCRunLoopThread.m */, + 34879BB719F50AD200E961F2 /* ConfigureRunLoopSource */, + 34879B9119F4D0E100E961F2 /* Images.xcassets */, + 34879B9319F4D0E100E961F2 /* LaunchScreen.xib */, + 34879B8419F4D0E100E961F2 /* Supporting Files */, + ); + path = RunLoopDemo; + sourceTree = ""; + }; + 34879B8419F4D0E100E961F2 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 34879B8519F4D0E100E961F2 /* Info.plist */, + 34879B8619F4D0E100E961F2 /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 34879B9D19F4D0E100E961F2 /* RunLoopDemoTests */ = { + isa = PBXGroup; + children = ( + 34879BA019F4D0E100E961F2 /* RunLoopDemoTests.m */, + 34879B9E19F4D0E100E961F2 /* Supporting Files */, + ); + path = RunLoopDemoTests; + sourceTree = ""; + }; + 34879B9E19F4D0E100E961F2 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 34879B9F19F4D0E100E961F2 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 34879BB719F50AD200E961F2 /* ConfigureRunLoopSource */ = { + isa = PBXGroup; + children = ( + 34879BB819F50ADA00E961F2 /* CCRunLoopInputSource.h */, + 34879BB919F50ADA00E961F2 /* CCRunLoopInputSource.m */, + 34879BBA19F50ADA00E961F2 /* CCRunLoopCustomInputSourceThread.h */, + 34879BBB19F50ADA00E961F2 /* CCRunLoopCustomInputSourceThread.m */, + ); + name = ConfigureRunLoopSource; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 34879B8019F4D0E100E961F2 /* RunLoopDemo */ = { + isa = PBXNativeTarget; + buildConfigurationList = 34879BA419F4D0E100E961F2 /* Build configuration list for PBXNativeTarget "RunLoopDemo" */; + buildPhases = ( + 34879B7D19F4D0E100E961F2 /* Sources */, + 34879B7E19F4D0E100E961F2 /* Frameworks */, + 34879B7F19F4D0E100E961F2 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = RunLoopDemo; + productName = RunLoopDemo; + productReference = 34879B8119F4D0E100E961F2 /* RunLoopDemo.app */; + productType = "com.apple.product-type.application"; + }; + 34879B9919F4D0E100E961F2 /* RunLoopDemoTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 34879BA719F4D0E100E961F2 /* Build configuration list for PBXNativeTarget "RunLoopDemoTests" */; + buildPhases = ( + 34879B9619F4D0E100E961F2 /* Sources */, + 34879B9719F4D0E100E961F2 /* Frameworks */, + 34879B9819F4D0E100E961F2 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 34879B9C19F4D0E100E961F2 /* PBXTargetDependency */, + ); + name = RunLoopDemoTests; + productName = RunLoopDemoTests; + productReference = 34879B9A19F4D0E100E961F2 /* RunLoopDemoTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 34879B7919F4D0E100E961F2 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0600; + ORGANIZATIONNAME = "Chun Tips"; + TargetAttributes = { + 34879B8019F4D0E100E961F2 = { + CreatedOnToolsVersion = 6.0.1; + DevelopmentTeam = 44U6VX5R2F; + }; + 34879B9919F4D0E100E961F2 = { + CreatedOnToolsVersion = 6.0.1; + TestTargetID = 34879B8019F4D0E100E961F2; + }; + }; + }; + buildConfigurationList = 34879B7C19F4D0E100E961F2 /* Build configuration list for PBXProject "RunLoopDemo" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 34879B7819F4D0E100E961F2; + productRefGroup = 34879B8219F4D0E100E961F2 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 34879B8019F4D0E100E961F2 /* RunLoopDemo */, + 34879B9919F4D0E100E961F2 /* RunLoopDemoTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 34879B7F19F4D0E100E961F2 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 34879B9519F4D0E100E961F2 /* LaunchScreen.xib in Resources */, + 34879B9219F4D0E100E961F2 /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 34879B9819F4D0E100E961F2 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 34879B7D19F4D0E100E961F2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 34879BC419F50B0300E961F2 /* CCAppDelegate.m in Sources */, + 34879BC519F50B0300E961F2 /* CCTestRunLoopViewController.m in Sources */, + 34879BBC19F50ADA00E961F2 /* CCRunLoopInputSource.m in Sources */, + 34879BBD19F50ADA00E961F2 /* CCRunLoopCustomInputSourceThread.m in Sources */, + 34879B8719F4D0E100E961F2 /* main.m in Sources */, + 0C648F7C1E1B5F580019AD64 /* TestTableViewController.m in Sources */, + 34879BC619F50B0300E961F2 /* CCRunLoopThread.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 34879B9619F4D0E100E961F2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 34879BA119F4D0E100E961F2 /* RunLoopDemoTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 34879B9C19F4D0E100E961F2 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 34879B8019F4D0E100E961F2 /* RunLoopDemo */; + targetProxy = 34879B9B19F4D0E100E961F2 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 34879B9319F4D0E100E961F2 /* LaunchScreen.xib */ = { + isa = PBXVariantGroup; + children = ( + 34879B9419F4D0E100E961F2 /* Base */, + ); + name = LaunchScreen.xib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 34879BA219F4D0E100E961F2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 34879BA319F4D0E100E961F2 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 34879BA519F4D0E100E961F2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = 44U6VX5R2F; + INFOPLIST_FILE = RunLoopDemo/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 34879BA619F4D0E100E961F2 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = 44U6VX5R2F; + INFOPLIST_FILE = RunLoopDemo/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 34879BA819F4D0E100E961F2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = RunLoopDemoTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/RunLoopDemo.app/RunLoopDemo"; + }; + name = Debug; + }; + 34879BA919F4D0E100E961F2 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + INFOPLIST_FILE = RunLoopDemoTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/RunLoopDemo.app/RunLoopDemo"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 34879B7C19F4D0E100E961F2 /* Build configuration list for PBXProject "RunLoopDemo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 34879BA219F4D0E100E961F2 /* Debug */, + 34879BA319F4D0E100E961F2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 34879BA419F4D0E100E961F2 /* Build configuration list for PBXNativeTarget "RunLoopDemo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 34879BA519F4D0E100E961F2 /* Debug */, + 34879BA619F4D0E100E961F2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 34879BA719F4D0E100E961F2 /* Build configuration list for PBXNativeTarget "RunLoopDemoTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 34879BA819F4D0E100E961F2 /* Debug */, + 34879BA919F4D0E100E961F2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 34879B7919F4D0E100E961F2 /* Project object */; +} diff --git a/RunLoopDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/RunLoopDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100755 index 0000000..0da4605 --- /dev/null +++ b/RunLoopDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/RunLoopDemo/Base.lproj/LaunchScreen.xib b/RunLoopDemo/Base.lproj/LaunchScreen.xib new file mode 100755 index 0000000..4c85428 --- /dev/null +++ b/RunLoopDemo/Base.lproj/LaunchScreen.xib @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RunLoopDemo/CCAppDelegate.h b/RunLoopDemo/CCAppDelegate.h new file mode 100755 index 0000000..8ebb2e1 --- /dev/null +++ b/RunLoopDemo/CCAppDelegate.h @@ -0,0 +1,26 @@ +// +// AppDelegate.h +// RunLoopDemo +// +// Created by Chun Ye on 10/20/14. +// Copyright (c) 2014 Chun Tips. All rights reserved. +// + +#import +#import "CCRunLoopInputSource.h" + +@interface CCAppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end + +@interface CCAppDelegate (RunLoop) + +- (void)registerSource:(CCRunLoopContext *)sourceContext; + +- (void)removeSource:(CCRunLoopContext *)sourceContext; + +- (void)testInputSourceEvent; + +@end \ No newline at end of file diff --git a/RunLoopDemo/CCAppDelegate.m b/RunLoopDemo/CCAppDelegate.m new file mode 100755 index 0000000..bb3f425 --- /dev/null +++ b/RunLoopDemo/CCAppDelegate.m @@ -0,0 +1,93 @@ +// +// AppDelegate.m +// RunLoopDemo +// +// Created by Chun Ye on 10/20/14. +// Copyright (c) 2014 Chun Tips. All rights reserved. +// + +#import "CCAppDelegate.h" +#import "CCTestRunLoopViewController.h" +#import "CCRunLoopThread.h" +#import "CCRunLoopCustomInputSourceThread.h" + +#define kTestRunLoopThread 0 +#define kTestCustomInputSpurceRunLoopThread 1 + +@interface CCAppDelegate () + +@property (nonatomic, strong) NSMutableArray *sources; + +@end + +@implementation CCAppDelegate + + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + + self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + self.window.backgroundColor = [UIColor whiteColor]; + + CCTestRunLoopViewController *testViewController = [[CCTestRunLoopViewController alloc] init]; + UINavigationController * nav = [[UINavigationController alloc]initWithRootViewController:testViewController]; + self.window.rootViewController = nav; + + [self.window makeKeyAndVisible]; + + if (kTestRunLoopThread) { + [self startRunLoopThread]; + } + + if (kTestCustomInputSpurceRunLoopThread) { + [self startCustomInputSpurceRunLoopThread]; + } + + return YES; +} + +#pragma mark - Private + +- (void)startRunLoopThread +{ + CCRunLoopThread *runLoopThread = [[CCRunLoopThread alloc] init]; + [runLoopThread start]; +} + +- (void)startCustomInputSpurceRunLoopThread +{ + CCRunLoopCustomInputSourceThread *customInputSourceThread = [[CCRunLoopCustomInputSourceThread alloc] init]; + [customInputSourceThread start]; +} + +@end + +@implementation CCAppDelegate (RunLoop) + +- (void)registerSource:(CCRunLoopContext *)sourceContext +{ + if (!self.sources) { + self.sources = [NSMutableArray array]; + } + [self.sources addObject:sourceContext]; +} + +- (void)removeSource:(CCRunLoopContext *)sourceContext +{ + [self.sources enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + CCRunLoopContext *context = obj; + if ([context isEqual:sourceContext]) { + [self.sources removeObject:context]; + *stop = YES; + } + }]; +} + +- (void)testInputSourceEvent +{ + CCRunLoopContext *runLoopContext = [self.sources objectAtIndex:0]; + CCRunLoopInputSource *inputSource = runLoopContext.runLoopInputSource; + [inputSource addTestPrintCommandWithString:[[NSDate date] description]]; + [inputSource fireAllCommandsOnRunLoop:runLoopContext.runLoop]; +} + +@end diff --git a/RunLoopDemo/CCRunLoopCustomInputSourceThread.h b/RunLoopDemo/CCRunLoopCustomInputSourceThread.h new file mode 100755 index 0000000..dfb6875 --- /dev/null +++ b/RunLoopDemo/CCRunLoopCustomInputSourceThread.h @@ -0,0 +1,13 @@ +// +// CCRunLoopCustomInputSourceThread.h +// RunLoopDemo +// +// Created by Chun Ye on 10/20/14. +// Copyright (c) 2014 Chun Tips. All rights reserved. +// + +#import + +@interface CCRunLoopCustomInputSourceThread : NSThread + +@end diff --git a/RunLoopDemo/CCRunLoopCustomInputSourceThread.m b/RunLoopDemo/CCRunLoopCustomInputSourceThread.m new file mode 100755 index 0000000..a984b2f --- /dev/null +++ b/RunLoopDemo/CCRunLoopCustomInputSourceThread.m @@ -0,0 +1,61 @@ +// +// CCRunLoopCustomInputSourceThread.m +// RunLoopDemo +// +// Created by Chun Ye on 10/20/14. +// Copyright (c) 2014 Chun Tips. All rights reserved. +// + +#import "CCRunLoopCustomInputSourceThread.h" +#import "CCRunLoopInputSource.h" + +@interface CCRunLoopCustomInputSourceThread () + +@property (nonatomic, strong) CCRunLoopInputSource *customInputSource; + +@end + +@implementation CCRunLoopCustomInputSourceThread + +- (void)main +{ + @autoreleasepool { + NSLog(@"CCRunLoopCustomInputSourceThread Enter"); + + NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop]; + + self.customInputSource = [[CCRunLoopInputSource alloc] init]; + self.customInputSource.delegate = self; + [self.customInputSource addToCurrentRunLoop]; + + while (!self.cancelled) { + NSLog(@"Enter Run Loop"); + + // print test string; + [self finishOtherTask]; + + [currentRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; + + NSLog(@"Exit Run Loop"); + } + + NSLog(@"CCRunLoopCustomInputSourceThread Exit"); + } +} + +- (void)finishOtherTask +{ + NSLog(@"Begin finishOtherTask"); + NSLog(@"🌹🌹🌹🌹🌹🌹🌹🌹🌹🌹🌹"); + NSLog(@"🌹🌹🌹🌹🌹🌹🌹🌹🌹🌹🌹"); + NSLog(@"End finishOtherTask"); +} + +#pragma mark - CCRunLoopInputSourceTestDelegate + +- (void)activeInputSourceForTestPrintStringEvent:(NSString *)string +{ + NSLog(@"activeInputSourceForTestPrintStringEvent : %@", string); +} + +@end diff --git a/RunLoopDemo/CCRunLoopInputSource.h b/RunLoopDemo/CCRunLoopInputSource.h new file mode 100755 index 0000000..3211f4e --- /dev/null +++ b/RunLoopDemo/CCRunLoopInputSource.h @@ -0,0 +1,46 @@ +// +// CCRunLoopInputSource.h +// RunLoopDemo +// +// Created by Chun Ye on 10/20/14. +// Copyright (c) 2014 Chun Tips. All rights reserved. +// + +#import + +@protocol CCRunLoopInputSourceTestDelegate + +- (void)activeInputSourceForTestPrintStringEvent:(NSString *)string; + +@end + +@interface CCRunLoopInputSource : NSObject + + +@property (nonatomic, weak) id delegate; + +// 初始化和销毁 +- (instancetype)init; +- (void)addToCurrentRunLoop; +- (void)invalidate; + +// 处理事件 +- (void)inputSourceFired; + +// 其他线程注册事件 +- (void)addCommand:(NSInteger)command data:(NSData *)data; +- (void)addTestPrintCommandWithString:(NSString *)string; + +- (void)fireAllCommandsOnRunLoop:(CFRunLoopRef)runLoop; + +@end + +// 容器类,用来保存和传递数据 +@interface CCRunLoopContext : NSObject + +@property (nonatomic, readonly) CFRunLoopRef runLoop; +@property (nonatomic, readonly) CCRunLoopInputSource *runLoopInputSource; + +- (instancetype)initWithSource:(CCRunLoopInputSource *)runLoopInputSource runLoop:(CFRunLoopRef)runLoop; + +@end \ No newline at end of file diff --git a/RunLoopDemo/CCRunLoopInputSource.m b/RunLoopDemo/CCRunLoopInputSource.m new file mode 100755 index 0000000..7587700 --- /dev/null +++ b/RunLoopDemo/CCRunLoopInputSource.m @@ -0,0 +1,129 @@ +// +// CCRunLoopInputSource.m +// RunLoopDemo +// +// Created by Chun Ye on 10/20/14. +// Copyright (c) 2014 Chun Tips. All rights reserved. +// + +#import "CCRunLoopInputSource.h" +#import "CCAppDelegate.h" + +@interface CCRunLoopInputSource () +{ + CFRunLoopSourceRef _runLoopSource; + NSMutableArray *_commands; + NSString *_testPrintString; +} + +@end + +/* Run Loop Source Context的三个回调方法 */ + +// 当把当前的Run Loop Source添加到Run Loop中时,会回调这个方法。主线程管理该Input source,所以使用performSelectorOnMainThread通知主线程。主线程和当前线程的通信使用CCRunLoopContext对象来完成。 +void runLoopSourceScheduleRoutine (void *info, CFRunLoopRef runLoopRef, CFStringRef mode) +{ + CCRunLoopInputSource *runLoopInputSource = (__bridge CCRunLoopInputSource *)info; + CCAppDelegate *appDelegate = [UIApplication sharedApplication].delegate; + + CCRunLoopContext *runLoopContext = [[CCRunLoopContext alloc] initWithSource:runLoopInputSource runLoop:runLoopRef]; + [appDelegate performSelectorOnMainThread:@selector(registerSource:) withObject:runLoopContext waitUntilDone:NO]; +} + +// 当前Input source被告知需要处理事件的回调方法 +void runLoopSourcePerformRoutine (void *info) +{ + CCRunLoopInputSource *runLoopInputSource = (__bridge CCRunLoopInputSource *)info; + [runLoopInputSource inputSourceFired]; +} + +// 如果使用CFRunLoopSourceInvalidate函数把输入源从Run Loop里面移除的话,系统会回调该方法。我们在该方法中移除了主线程对当前Input source context的引用。 +void runLoopSourceCancelRoutine (void *info, CFRunLoopRef runLoopRef, CFStringRef mode) +{ + CCRunLoopInputSource *runLoopInputSource = (__bridge CCRunLoopInputSource *)info; + CCAppDelegate *appDelegate = [UIApplication sharedApplication].delegate; + + CCRunLoopContext *runLoopContext = [[CCRunLoopContext alloc] initWithSource:runLoopInputSource runLoop:runLoopRef]; + [appDelegate performSelectorOnMainThread:@selector(removeSource:) withObject:runLoopContext waitUntilDone:YES]; +} + +@implementation CCRunLoopInputSource + +#pragma mark - Public + +- (instancetype)init +{ + self = [super init]; + if (self) { + CFRunLoopSourceContext context = {0, (__bridge void *)(self), NULL, NULL, NULL, NULL, NULL, + &runLoopSourceScheduleRoutine, + &runLoopSourceCancelRoutine, + &runLoopSourcePerformRoutine}; + + _runLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context); + + _commands = [NSMutableArray array]; + } + return self; +} + +- (void)addToCurrentRunLoop +{ + CFRunLoopRef runLoop = CFRunLoopGetCurrent(); + CFRunLoopAddSource(runLoop, _runLoopSource, kCFRunLoopDefaultMode); +} + +- (void)invalidate +{ + CFRunLoopRef runLoop = CFRunLoopGetCurrent(); + CFRunLoopRemoveSource(runLoop, _runLoopSource, kCFRunLoopDefaultMode); +} + +- (void)inputSourceFired +{ + NSLog(@"Enter inputSourceFired"); + + // Test + if (_testPrintString) { + if ([self.delegate respondsToSelector:@selector(activeInputSourceForTestPrintStringEvent:)]) { + [self.delegate activeInputSourceForTestPrintStringEvent:_testPrintString]; + } + } + + NSLog(@"Exit inputSourceFired"); +} + +- (void)addCommand:(NSInteger)command data:(NSData *)data +{ + +} + +- (void)addTestPrintCommandWithString:(NSString *)string +{ + NSLog(@"Current Thread: %@", [NSThread currentThread]); + _testPrintString = string; +} + +- (void)fireAllCommandsOnRunLoop:(CFRunLoopRef)runLoop +{ + NSLog(@"Current Thread: %@", [NSThread currentThread]); + + CFRunLoopSourceSignal(_runLoopSource); + CFRunLoopWakeUp(runLoop); +} + +@end + +@implementation CCRunLoopContext + +- (instancetype)initWithSource:(CCRunLoopInputSource *)runLoopInputSource runLoop:(CFRunLoopRef)runLoop +{ + self = [super init]; + if (self) { + _runLoopInputSource = runLoopInputSource; + _runLoop = runLoop; + } + return self; +} + +@end diff --git a/RunLoopDemo/CCRunLoopThread.h b/RunLoopDemo/CCRunLoopThread.h new file mode 100755 index 0000000..33c5ec0 --- /dev/null +++ b/RunLoopDemo/CCRunLoopThread.h @@ -0,0 +1,13 @@ +// +// CCRunLoopThread.h +// RunLoopDemo +// +// Created by Chun Ye on 10/20/14. +// Copyright (c) 2014 Chun Tips. All rights reserved. +// + +#import + +@interface CCRunLoopThread : NSThread + +@end diff --git a/RunLoopDemo/CCRunLoopThread.m b/RunLoopDemo/CCRunLoopThread.m new file mode 100755 index 0000000..38206f5 --- /dev/null +++ b/RunLoopDemo/CCRunLoopThread.m @@ -0,0 +1,107 @@ +// +// CCRunLoopThread.m +// RunLoopDemo +// +// Created by Chun Ye on 10/20/14. +// Copyright (c) 2014 Chun Tips. All rights reserved. +// + +#import "CCRunLoopThread.h" + +#define kUseParticularModeToStartRunLoop 0 + +@implementation CCRunLoopThread +{ + NSInteger _timerIndex; +} + +- (void)main +{ + @autoreleasepool { + NSLog(@"Thread Enter"); + + NSRunLoop *currentThreadRunLoop = [NSRunLoop currentRunLoop]; + // 或者 + // CFRunLoopRef currentThreadRunLoop = CFRunLoopGetCurrent(); + + // 创建一个 Run Loop Observer,并添加到当前Run Loop中, 设置Mode为Default + CFRunLoopObserverContext context = {0, (__bridge void *)(self), NULL, NULL, NULL}; + CFRunLoopObserverRef observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, ¤tRunLoopObserver, &context); + + if (observer) { + CFRunLoopRef runLoopRef = currentThreadRunLoop.getCFRunLoop; + CFRunLoopAddObserver(runLoopRef, observer, kCFRunLoopDefaultMode); + } + + // 创建一个Timer,重复调用来驱动Run Loop + [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(handleTimerTask) userInfo:nil repeats:YES]; + + NSInteger loopCount = 10; + + // 执行Run Loop10次后退出,每次Run Loop返回的时候检查是否有使线程退出的条件成立 + do { + NSLog(@"LoopCount: %ld", loopCount); + if (kUseParticularModeToStartRunLoop) { + [currentThreadRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; + } else { + [currentThreadRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]]; + } + loopCount --; + } while (loopCount); + + NSLog(@"Thread Exit"); + } +} + +#pragma mark - Observer CallBack + +void currentRunLoopObserver(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) +{ + NSLog(@"Current thread Run Loop activity: %@", printActivity(activity)); +} + +static inline NSString* printActivity(CFRunLoopActivity activity) +{ + NSString *activityDescription; + switch (activity) { + case kCFRunLoopEntry: + activityDescription = @"kCFRunLoopEntry"; + break; + case kCFRunLoopBeforeTimers: + activityDescription = @"kCFRunLoopBeforeTimers"; + break; + case kCFRunLoopBeforeSources: + activityDescription = @"kCFRunLoopBeforeSources"; + break; + case kCFRunLoopBeforeWaiting: + activityDescription = @"kCFRunLoopBeforeWaiting"; + break; + case kCFRunLoopAfterWaiting: + activityDescription = @"kCFRunLoopAfterWaiting"; + break; + case kCFRunLoopExit: + activityDescription = @"kCFRunLoopExit"; + break; + default: + break; + } + return activityDescription; +} + +#pragma mark - Actions + +- (void)handleTimerTask +{ + NSLog(@"handleTimerTask"); + + // 只有在上面do while循环中使用-runMode:beforDate才有效 + if (kUseParticularModeToStartRunLoop) { + _timerIndex ++; + NSLog(@"timer Index : %ld", _timerIndex); + if (_timerIndex > 5) { + CFRunLoopStop(CFRunLoopGetCurrent()); //只有在-runMode:beforDate 和 -run 两种情况下有效 + } + } +} + +@end diff --git a/RunLoopDemo/CCTestRunLoopViewController.h b/RunLoopDemo/CCTestRunLoopViewController.h new file mode 100755 index 0000000..5596384 --- /dev/null +++ b/RunLoopDemo/CCTestRunLoopViewController.h @@ -0,0 +1,18 @@ +// +// CCViewController.h +// RunLoopDemo +// +// Created by Chun Ye on 10/20/14. +// Copyright (c) 2014 Chun Tips. All rights reserved. +// + +#import + +/* + 测试如何使用Run Loop阻塞线程,等待其他线程执行后再执行操作。 + */ +@interface CCTestRunLoopViewController : UIViewController + + +@end + diff --git a/RunLoopDemo/CCTestRunLoopViewController.m b/RunLoopDemo/CCTestRunLoopViewController.m new file mode 100755 index 0000000..35a24b8 --- /dev/null +++ b/RunLoopDemo/CCTestRunLoopViewController.m @@ -0,0 +1,186 @@ +// +// CCViewController.m +// RunLoopDemo +// +// Created by Chun Ye on 10/20/14. +// Copyright (c) 2014 Chun Tips. All rights reserved. +// + +#import "CCTestRunLoopViewController.h" +#import "CCAppDelegate.h" + +#import "TestTableViewController.h" + +@interface CCTestRunLoopViewController () + +@property (nonatomic) BOOL normalThreadDidFinishFlag; +@property (nonatomic) BOOL runLoopThreadDidFinishFlag; + +@end + +@implementation CCTestRunLoopViewController + +- (void)viewDidLoad +{ + [super viewDidLoad]; + [self setNav]; + + [[UIButton appearance] setBackgroundColor:[UIColor blueColor]]; + + /* 点击之后 产生一个普通的Thread执行任务,线程完成之后再继续运行。 在这个过程中 会阻塞UI线程。点击下面的Normal按钮没有输出。 */ + UIButton *normalThreadButton = [[UIButton alloc] initWithFrame:CGRectMake(10, 30+64, 200, 50)]; + [normalThreadButton setTitle:@"Normal Thread" forState:UIControlStateNormal]; + [normalThreadButton addTarget:self action:@selector(handleNormalThreadButtonTouchUpInside) forControlEvents:UIControlEventTouchUpInside]; + [self.view addSubview:normalThreadButton]; + + /* 点击之后 启动一个线程,使用Run Loop,等待线程完成后再继续执行任务。 在这个过程中 不会阻塞UI线程。点击下面的Normal按钮会正常输出。 */ + UIButton *runLoopThreadButton = [[UIButton alloc] initWithFrame:CGRectMake(10, 100+64, 200, 50)]; + [runLoopThreadButton setTitle:@"Run Loop Thread" forState:UIControlStateNormal]; + [runLoopThreadButton addTarget:self action:@selector(handleRunLoopThreadButtonTouchUpInside) forControlEvents:UIControlEventTouchUpInside]; + [self.view addSubview:runLoopThreadButton]; + + /* 测试Button 看UI是否能正常响应 */ + UIButton *normalButton = [[UIButton alloc] initWithFrame:CGRectMake(10, 170+64, 200, 50)]; + [normalButton setTitle:@"Normal" forState:UIControlStateNormal]; + [normalButton addTarget:self action:@selector(handleNormalButtonTouchUpInside) forControlEvents:UIControlEventTouchUpInside]; + [self.view addSubview:normalButton]; + + /* Test Run Loop Custom Source Thread Button */ + { + UIButton *testCustomSourceButton = [[UIButton alloc] initWithFrame:CGRectMake(10, 300+64, 300, 50)]; + [testCustomSourceButton setTitle:@"Test Custom Source" forState:UIControlStateNormal]; + [testCustomSourceButton addTarget:self action:@selector(handleTestCustomSourceButtonTouchUpInside) forControlEvents:UIControlEventTouchUpInside]; + [self.view addSubview:testCustomSourceButton]; + } + } + +-(void)setNav{ + self.title = @"test runLoop"; +// UIButton * pushBtn = [UIButton new]; +// pushBtn.backgroundColor = [UIColor whiteColor]; +// [pushBtn addTarget:self action:@selector(clickToPushToTableView) forControlEvents:UIControlEventTouchUpInside]; +// [pushBtn setTitle:@"to Table" forState:UIControlStateNormal]; +// pushBtn.titleLabel.font = [UIFont systemFontOfSize:13]; +// pushBtn.bounds = CGRectMake(0, 0, 100, 40); +// UIBarButtonItem * barBtn = [[UIBarButtonItem alloc]initWithCustomView:pushBtn]; + UIBarButtonItem * barB = [[UIBarButtonItem alloc]initWithTitle:@"to Table" style:UIBarButtonItemStyleBordered target:self action:@selector(clickToPushToTableView)]; + self.navigationItem.rightBarButtonItem = barB; + +} +-(void)clickToPushToTableView{ + NSLog(@"click"); + TestTableViewController * testVC = [TestTableViewController new]; + [self.navigationController pushViewController:testVC animated:YES]; +} +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +#pragma mark - Action Handler + +- (void)handleNormalThreadButtonTouchUpInside +{ + NSLog(@"Enter handleNormalThreadButtonTouchUpInside"); + + self.normalThreadDidFinishFlag = NO; + + NSLog(@"Start a New Normal Thread"); + NSThread *normalThread = [[NSThread alloc] initWithTarget:self selector:@selector(handleNormalThreadTask) object:nil]; + [normalThread start]; + + //等待线程完成再执行以下任务,在这种情况下会阻塞UI线程 + while (!self.normalThreadDidFinishFlag) { + NSLog(@"wait and judge finished or not "); + [NSThread sleepForTimeInterval:0.5]; + } + + //直到线程执行完成,才会打印handleNormalButtonTouchUpInside中的输出信息 + NSLog(@"Exit handleNormalThreadButtonTouchUpInside"); +} + +- (void)handleRunLoopThreadButtonTouchUpInside +{ + NSLog(@"Enter handleRunLoopThreadButtonTouchUpInside"); + + self.runLoopThreadDidFinishFlag = NO; + + NSLog(@"Start a New Run Loop Thread"); + NSThread *runLoopThread = [[NSThread alloc] initWithTarget:self selector:@selector(handleRunLoopThreadTask) object:nil]; + [runLoopThread start]; + NSLog(@"current thread == %@",runLoopThread); // 5 + + //使用Run Loop,在线程执行期间,handleNormalButtonTouchUpInside能够正常输入信息 + while (!self.runLoopThreadDidFinishFlag) { + NSLog(@"Begin RunLoop"); + + NSLog(@"currentRunLoop thread == %@,",[NSThread currentThread]); // 1 main + [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; + + NSLog(@"End RunLoop"); + } + + //Run Loop 真神奇 + NSLog(@"Exit handleRunLoopThreadButtonTouchUpInside"); + + NSLog(@"After ending runLoop,current thread == %@",runLoopThread); // 5 +} + +- (void)handleNormalButtonTouchUpInside +{ + NSLog(@"Enter handleNormalButtonTouchUpInside"); + + NSLog(@"Exit handleNormalButtonTouchUpInside"); +} + +- (void)handleTestCustomSourceButtonTouchUpInside +{ + CCAppDelegate *appDelegate = [UIApplication sharedApplication].delegate; + [appDelegate testInputSourceEvent]; +} + +#pragma mark - Private + +- (void)handleNormalThreadTask +{ + NSLog(@"Enter Normal Thread"); + + for (NSInteger i = 0; i < 5; i ++) { + NSLog(@"In Normal Thread, count = %ld", i); + sleep(1); + } + + _normalThreadDidFinishFlag = YES; + + NSLog(@"Exit Normal Thread"); +} + +- (void)handleRunLoopThreadTask +{ + NSLog(@"Enter Run Loop Thread"); + + for (NSInteger i = 0; i < 5; i ++) { + NSLog(@"In Run Loop Thread, count = %ld, then sleep 1", i); + sleep(1); + } + +#if 0 + // 错误示范 + _runLoopThreadDidFinishFlag = YES; + // 这个时候并不能执行线程完成之后的任务,因为Run Loop所在的线程并不知道runLoopThreadDidFinishFlag被重新赋值。Run Loop这个时候没有被任务事件源唤醒。 + // 你会发现这个时候点击屏幕中的UI,线程将会继续执行。 因为Run Loop被UI事件唤醒。 + // 正确的做法是使用 "selector"方法唤醒Run Loop。 即如下: +#else + [self performSelectorOnMainThread:@selector(updateRunLoopThreadDidFinishFlag) withObject:nil waitUntilDone:NO]; // go to main thread to handle +#endif + + NSLog(@"Exit Run Loop Thread"); +} + +- (void)updateRunLoopThreadDidFinishFlag +{ + _runLoopThreadDidFinishFlag = YES; +} + +@end diff --git a/RunLoopDemo/Images.xcassets/AppIcon.appiconset/Contents.json b/RunLoopDemo/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100755 index 0000000..118c98f --- /dev/null +++ b/RunLoopDemo/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,38 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/RunLoopDemo/Info.plist b/RunLoopDemo/Info.plist new file mode 100755 index 0000000..faaf2b6 --- /dev/null +++ b/RunLoopDemo/Info.plist @@ -0,0 +1,36 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + chun.tips.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + + diff --git a/RunLoopDemo/TestTableViewController.h b/RunLoopDemo/TestTableViewController.h new file mode 100644 index 0000000..23f1bb9 --- /dev/null +++ b/RunLoopDemo/TestTableViewController.h @@ -0,0 +1,13 @@ +// +// TestTableViewController.h +// RunLoopDemo +// +// Created by 赵洋 on 17/1/3. +// Copyright © 2017年 Chun Tips. All rights reserved. +// + +#import + +@interface TestTableViewController : UITableViewController + +@end diff --git a/RunLoopDemo/TestTableViewController.m b/RunLoopDemo/TestTableViewController.m new file mode 100644 index 0000000..4492bc9 --- /dev/null +++ b/RunLoopDemo/TestTableViewController.m @@ -0,0 +1,133 @@ +// +// TestTableViewController.m +// RunLoopDemo +// +// Created by 赵洋 on 17/1/3. +// Copyright © 2017年 Chun Tips. All rights reserved. +// + +#import "TestTableViewController.h" + +@interface TestTableViewController () + +@property (nonatomic, strong) UILabel *testLabel; +@property (nonatomic) NSInteger count; +@property (nonatomic, strong) NSTimer *testTimer; + +@end + +@implementation TestTableViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + + self.count = 0; + + self.testLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 100, 100, 50)]; + [self.view addSubview:self.testLabel]; + + /// 当tablview 滚动时,label停止更新 scheduledTimer 默认运行在Default Mode +// self.testTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(updateTestLabel) userInfo:nil repeats:YES]; + /// --------- timer 添加至 commonModes, 当tableview滑动时 timer继续运行 + self.testTimer = [NSTimer timerWithTimeInterval:0.5 target:self selector:@selector(updateTestLabel) userInfo:nil repeats:YES]; + [[NSRunLoop currentRunLoop] addTimer:self.testTimer forMode:NSRunLoopCommonModes]; +} + +- (void)updateTestLabel +{ + self.count ++; + self.testLabel.text = [NSString stringWithFormat:@"%ld", self.count]; + if (self.count == 100) { + [self.testTimer invalidate]; + self.testTimer = nil; + } +} + +// 注意 --- 如果不在viewDidDisappear 中 invalidate timer 那么 dealloc不会走! +-(void)dealloc{ + NSLog(@"%s",__func__); +} + +-(void)viewDidDisappear:(BOOL)animated{ + + [super viewDidDisappear:animated]; + // ------上句👆、 下句👇 顺序可以调换 + if(self.testTimer){ + [self.testTimer invalidate]; + self.testTimer = nil; + } +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +#pragma mark - Table view data source + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { +#warning Incomplete implementation, return the number of sections + return 0; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { +#warning Incomplete implementation, return the number of rows + return 0; +} + +/* +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:<#@"reuseIdentifier"#> forIndexPath:indexPath]; + + // Configure the cell... + + return cell; +} +*/ + +/* +// Override to support conditional editing of the table view. +- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { + // Return NO if you do not want the specified item to be editable. + return YES; +} +*/ + +/* +// Override to support editing the table view. +- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { + if (editingStyle == UITableViewCellEditingStyleDelete) { + // Delete the row from the data source + [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; + } else if (editingStyle == UITableViewCellEditingStyleInsert) { + // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view + } +} +*/ + +/* +// Override to support rearranging the table view. +- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { +} +*/ + +/* +// Override to support conditional rearranging of the table view. +- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { + // Return NO if you do not want the item to be re-orderable. + return YES; +} +*/ + +/* +#pragma mark - Navigation + +// In a storyboard-based application, you will often want to do a little preparation before navigation +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. +} +*/ + +@end diff --git a/RunLoopDemo/main.m b/RunLoopDemo/main.m new file mode 100755 index 0000000..49c4455 --- /dev/null +++ b/RunLoopDemo/main.m @@ -0,0 +1,16 @@ +// +// main.m +// RunLoopDemo +// +// Created by Chun Ye on 10/20/14. +// Copyright (c) 2014 Chun Tips. All rights reserved. +// + +#import +#import "CCAppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([CCAppDelegate class])); + } +} diff --git a/RunLoopDemoTests/Info.plist b/RunLoopDemoTests/Info.plist new file mode 100755 index 0000000..327ecde --- /dev/null +++ b/RunLoopDemoTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + chun.tips.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/RunLoopDemoTests/RunLoopDemoTests.m b/RunLoopDemoTests/RunLoopDemoTests.m new file mode 100755 index 0000000..2323bf4 --- /dev/null +++ b/RunLoopDemoTests/RunLoopDemoTests.m @@ -0,0 +1,40 @@ +// +// RunLoopDemoTests.m +// RunLoopDemoTests +// +// Created by Chun Ye on 10/20/14. +// Copyright (c) 2014 Chun Tips. All rights reserved. +// + +#import +#import + +@interface RunLoopDemoTests : XCTestCase + +@end + +@implementation RunLoopDemoTests + +- (void)setUp { + [super setUp]; + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; +} + +- (void)testExample { + // This is an example of a functional test case. + XCTAssert(YES, @"Pass"); +} + +- (void)testPerformanceExample { + // This is an example of a performance test case. + [self measureBlock:^{ + // Put the code you want to measure the time of here. + }]; +} + +@end diff --git a/t1.txt b/t1.txt index e69de29..6f5a582 100644 --- a/t1.txt +++ b/t1.txt @@ -0,0 +1,7 @@ +sourcetree + +green: 新增 +yellow: 修改 +red: 移除 + +