Skip to content

Commit 61bd563

Browse files
committed
Move UIImagePickerController to sub-subspec
Fixes #3. Since today, app store submissions that contain code that reference privacy sensitive classes like Photos, Calendar or Location cause rejection. EVEN if the code in question is never used inside a third party library. Thus we are moving the ImagePickerController code to a sub-subspec.
1 parent 536f075 commit 61bd563

File tree

4 files changed

+99
-92
lines changed

4 files changed

+99
-92
lines changed

PMKUIKit.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
637E2C961D5C2E720043E370 /* TestUIViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 637E2C8F1D5C2E720043E370 /* TestUIViewController.m */; };
2222
637E2C971D5C2E720043E370 /* TestUIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 637E2C901D5C2E720043E370 /* TestUIViewController.swift */; };
2323
637E2C9B1D5C2F600043E370 /* infrastructure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 637E2C9A1D5C2F600043E370 /* infrastructure.swift */; };
24+
63A686811D88E93300D1C66B /* UIImagePickerController+Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63A6867E1D88E93300D1C66B /* UIImagePickerController+Promise.swift */; };
2425
63C7FFF71D5C020D003BAE60 /* PMKUIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63C7FFA71D5BEE09003BAE60 /* PMKUIKit.framework */; };
2526
63C9C4571D5D339900101ECE /* app.swift in Sources */ = {isa = PBXBuildFile; fileRef = 630B2DF41D5D0AD400DC10E9 /* app.swift */; };
2627
63C9C4581D5D339B00101ECE /* [email protected] in Resources */ = {isa = PBXBuildFile; fileRef = 630B2DF51D5D0AD400DC10E9 /* [email protected] */; };
@@ -91,6 +92,7 @@
9192
637E2C8F1D5C2E720043E370 /* TestUIViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TestUIViewController.m; path = Tests/TestUIViewController.m; sourceTree = SOURCE_ROOT; };
9293
637E2C901D5C2E720043E370 /* TestUIViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestUIViewController.swift; path = Tests/TestUIViewController.swift; sourceTree = SOURCE_ROOT; };
9394
637E2C9A1D5C2F600043E370 /* infrastructure.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = infrastructure.swift; path = Tests/infrastructure.swift; sourceTree = SOURCE_ROOT; };
95+
63A6867E1D88E93300D1C66B /* UIImagePickerController+Promise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIImagePickerController+Promise.swift"; path = "Sources/UIImagePickerController+Promise.swift"; sourceTree = SOURCE_ROOT; };
9496
63C700091D5C0253003BAE60 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
9597
63C7FFA71D5BEE09003BAE60 /* PMKUIKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PMKUIKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
9698
63C7FFF21D5C020D003BAE60 /* PMKUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PMKUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -178,6 +180,7 @@
178180
637E2C7A1D5C2E0B0043E370 /* UIViewController+AnyPromise.h */,
179181
637E2C7B1D5C2E0B0043E370 /* UIViewController+AnyPromise.m */,
180182
637E2C7C1D5C2E0B0043E370 /* UIViewController+Promise.swift */,
183+
63A6867E1D88E93300D1C66B /* UIImagePickerController+Promise.swift */,
181184
);
182185
name = Sources;
183186
path = "PMK+UIKit";
@@ -393,6 +396,7 @@
393396
isa = PBXSourcesBuildPhase;
394397
buildActionMask = 2147483647;
395398
files = (
399+
63A686811D88E93300D1C66B /* UIImagePickerController+Promise.swift in Sources */,
396400
637E2C7D1D5C2E0B0043E370 /* PMKAlertController.swift in Sources */,
397401
637E2C861D5C2E0B0043E370 /* UIView+Promise.swift in Sources */,
398402
637E2C891D5C2E0B0043E370 /* UIViewController+Promise.swift in Sources */,
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import UIKit
2+
#if !COCOAPODS
3+
import PromiseKit
4+
#endif
5+
6+
#if !os(tvOS)
7+
8+
extension UIViewController {
9+
@available(*, deprecated: 3.4, renamed: "promise(_:animate:fulfills:completion:)")
10+
public func promiseViewController(_ vc: UIImagePickerController, animated: Bool = true, completion: (() -> Void)? = nil) -> Promise<UIImage> {
11+
return promise(vc, animate: animated ? [.appear, .disappear] : [], completion: completion)
12+
}
13+
14+
@available(*, deprecated: 3.4, renamed: "promise(_:animate:fulfills:completion:)")
15+
public func promiseViewController(_ vc: UIImagePickerController, animated: Bool = true, completion: (() -> Void)? = nil) -> Promise<[String: AnyObject]> {
16+
return promise(vc, animate: animated ? [.appear, .disappear] : [], completion: completion)
17+
}
18+
19+
/// Presents the UIImagePickerController, resolving with the user action.
20+
public func promise(_ vc: UIImagePickerController, animate: PMKAnimationOptions = [.appear, .disappear], completion: (() -> Void)? = nil) -> Promise<UIImage> {
21+
let animated = animate.contains(.appear)
22+
let proxy = UIImagePickerControllerProxy()
23+
vc.delegate = proxy
24+
vc.mediaTypes = ["public.image"] // this promise can only resolve with a UIImage
25+
present(vc, animated: animated, completion: completion)
26+
return proxy.promise.then(on: zalgo) { info -> UIImage in
27+
if let img = info[UIImagePickerControllerEditedImage] as? UIImage {
28+
return img
29+
}
30+
if let img = info[UIImagePickerControllerOriginalImage] as? UIImage {
31+
return img
32+
}
33+
throw Error.noImageFound
34+
}.always {
35+
vc.presentingViewController?.dismiss(animated: animated, completion: nil)
36+
}
37+
}
38+
39+
/// Presents the UIImagePickerController, resolving with the user action.
40+
public func promise(_ vc: UIImagePickerController, animate: PMKAnimationOptions = [.appear, .disappear], completion: (() -> Void)? = nil) -> Promise<[String: Any]> {
41+
let animated = animate.contains(.appear)
42+
let proxy = UIImagePickerControllerProxy()
43+
vc.delegate = proxy
44+
present(vc, animated: animated, completion: completion)
45+
return proxy.promise.always {
46+
vc.presentingViewController?.dismiss(animated: animated, completion: nil)
47+
}
48+
}
49+
}
50+
51+
@objc private class UIImagePickerControllerProxy: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
52+
let (promise, fulfill, reject) = Promise<[String : Any]>.pending()
53+
var retainCycle: AnyObject?
54+
55+
required override init() {
56+
super.init()
57+
retainCycle = self
58+
}
59+
60+
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
61+
fulfill(info)
62+
retainCycle = nil
63+
}
64+
65+
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
66+
reject(UIImagePickerController.Error.cancelled)
67+
retainCycle = nil
68+
}
69+
}
70+
71+
extension UIImagePickerController {
72+
/// Errors representing PromiseKit UIImagePickerController failures
73+
public enum Error: CancellableError {
74+
/// The user cancelled the UIImagePickerController.
75+
case cancelled
76+
/// - Returns: true
77+
public var isCancelled: Bool {
78+
switch self {
79+
case .cancelled:
80+
return true
81+
}
82+
}
83+
}
84+
}
85+
86+
#endif

Sources/UIViewController+AnyPromise.m

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
#import <UIKit/UIImagePickerController.h>
21
#import <UIKit/UINavigationController.h>
32
#import "UIViewController+AnyPromise.h"
43
#import <PromiseKit/PromiseKit.h>
54

6-
#if TARGET_OS_TV
7-
#define UIImagePickerControllerDelegate UINavigationControllerDelegate
5+
#if PMKImagePickerController
6+
#import <UIKit/UIImagePickerController.h>
87
#endif
98

10-
11-
@interface PMKGenericDelegate : NSObject <UIImagePickerControllerDelegate, UINavigationControllerDelegate> {
9+
@interface PMKGenericDelegate : NSObject <UINavigationControllerDelegate> {
1210
@public
1311
PMKResolver resolve;
1412
}
@@ -31,10 +29,10 @@ - (AnyPromise *)promiseViewController:(UIViewController *)vc animated:(BOOL)anim
3129
PMKGenericDelegate *delegate = [PMKGenericDelegate delegateWithPromise:&promise];
3230
[vc setValue:delegate forKey:@"messageComposeDelegate"];
3331
}
34-
#if !TARGET_OS_TV
35-
else if ([vc isKindOfClass:NSClassFromString(@"UIImagePickerController")]) {
32+
#ifdef PMKImagePickerController
33+
else if ([vc isKindOfClass:[UIImagePickerController class]]) {
3634
PMKGenericDelegate *delegate = [PMKGenericDelegate delegateWithPromise:&promise];
37-
((UIImagePickerController *)vc).delegate = delegate;
35+
[vc setValue:delegate forKey:@"delegate"];
3836
}
3937
#endif
4038
else if ([vc isKindOfClass:NSClassFromString(@"SLComposeViewController")]) {
@@ -122,7 +120,8 @@ - (void)messageComposeViewController:(id)controller didFinishWithResult:(int)res
122120
retainCycle = nil;
123121
}
124122

125-
#if !TARGET_OS_TV
123+
#ifdef PMKImagePickerController
124+
126125
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
127126
id img = info[UIImagePickerControllerEditedImage] ?: info[UIImagePickerControllerOriginalImage];
128127
resolve(PMKManifold(img, info));
@@ -133,6 +132,7 @@ - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
133132
resolve([NSError cancelledError]);
134133
retainCycle = nil;
135134
}
135+
136136
#endif
137137

138138
@end

Sources/UIViewController+Promise.swift

Lines changed: 0 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -95,49 +95,6 @@ extension UIViewController {
9595
public func promiseViewController<T>(_ vc: UIViewController, animated: Bool = true, completion: (() -> Void)? = nil) -> Promise<T> {
9696
return promise(vc, animate: animated ? [.appear, .disappear] : [], completion: completion)
9797
}
98-
99-
#if !os(tvOS)
100-
@available(*, deprecated: 3.4, renamed: "promise(_:animate:fulfills:completion:)")
101-
public func promiseViewController(_ vc: UIImagePickerController, animated: Bool = true, completion: (() -> Void)? = nil) -> Promise<UIImage> {
102-
return promise(vc, animate: animated ? [.appear, .disappear] : [], completion: completion)
103-
}
104-
105-
@available(*, deprecated: 3.4, renamed: "promise(_:animate:fulfills:completion:)")
106-
public func promiseViewController(_ vc: UIImagePickerController, animated: Bool = true, completion: (() -> Void)? = nil) -> Promise<[String: AnyObject]> {
107-
return promise(vc, animate: animated ? [.appear, .disappear] : [], completion: completion)
108-
}
109-
110-
/// Presents the UIImagePickerController, resolving with the user action.
111-
public func promise(_ vc: UIImagePickerController, animate: PMKAnimationOptions = [.appear, .disappear], completion: (() -> Void)? = nil) -> Promise<UIImage> {
112-
let animated = animate.contains(.appear)
113-
let proxy = UIImagePickerControllerProxy()
114-
vc.delegate = proxy
115-
vc.mediaTypes = ["public.image"] // this promise can only resolve with a UIImage
116-
present(vc, animated: animated, completion: completion)
117-
return proxy.promise.then(on: zalgo) { info -> UIImage in
118-
if let img = info[UIImagePickerControllerEditedImage] as? UIImage {
119-
return img
120-
}
121-
if let img = info[UIImagePickerControllerOriginalImage] as? UIImage {
122-
return img
123-
}
124-
throw Error.noImageFound
125-
}.always {
126-
vc.presentingViewController?.dismiss(animated: animated, completion: nil)
127-
}
128-
}
129-
130-
/// Presents the UIImagePickerController, resolving with the user action.
131-
public func promise(_ vc: UIImagePickerController, animate: PMKAnimationOptions = [.appear, .disappear], completion: (() -> Void)? = nil) -> Promise<[String: Any]> {
132-
let animated = animate.contains(.appear)
133-
let proxy = UIImagePickerControllerProxy()
134-
vc.delegate = proxy
135-
present(vc, animated: animated, completion: completion)
136-
return proxy.promise.always {
137-
vc.presentingViewController?.dismiss(animated: animated, completion: nil)
138-
}
139-
}
140-
#endif
14198
}
14299

143100
/// A protocol for UIViewControllers that can be promised.
@@ -152,43 +109,3 @@ extension UIViewController {
152109
*/
153110
var promise: AnyObject! { get }
154111
}
155-
156-
157-
#if !os(tvOS)
158-
159-
@objc private class UIImagePickerControllerProxy: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
160-
let (promise, fulfill, reject) = Promise<[String : Any]>.pending()
161-
var retainCycle: AnyObject?
162-
163-
required override init() {
164-
super.init()
165-
retainCycle = self
166-
}
167-
168-
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
169-
fulfill(info)
170-
retainCycle = nil
171-
}
172-
173-
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
174-
reject(UIImagePickerController.Error.cancelled)
175-
retainCycle = nil
176-
}
177-
}
178-
179-
extension UIImagePickerController {
180-
/// Errors representing PromiseKit UIImagePickerController failures
181-
public enum Error: CancellableError {
182-
/// The user cancelled the UIImagePickerController.
183-
case cancelled
184-
/// - Returns: true
185-
public var isCancelled: Bool {
186-
switch self {
187-
case .cancelled:
188-
return true
189-
}
190-
}
191-
}
192-
}
193-
194-
#endif

0 commit comments

Comments
 (0)