While trying to setup email subject and content via UIActivityViewController
I worked with the .setValue
func in Swift. The key to set the subject was easy to find, but I couldn't find the key to set the content.
activityViewController.setValue("Subject", forKey: "Subject")
//Key "Content" is not defined
activityViewController.setValue("Content", forKey: "Content"
In this context I searched for a "list" with all possible keys, but I couldn't find anything (Even in the API doc from Apple https://developer.apple.com/documentation/objectivec/nsobject/1415969-setvalue). So I would like to ask in general where to find such a list, independent of this particular case.
You're accessing private internal details of UIActivityViewController
. There is no telling what that ivar is used for and under what conditions is it safe to set it. setValue(_:forKey:)
is a dynamic method that will let you access arbitrary internals, but that doesn't mean you should.
For exploratory purposes, you can use tools like class-dump
or Hopper to reverse engineer the class, or you can query it at runtime like this:
let cls = UIActivityViewController.self
var count: UInt32 = 0
let ivars = class_copyIvarList(cls, &count)!
for i in 0..<count {
let ivar = ivars[Int(i)]
let name = ivar_getName(ivar)!
print(String(cString: name))
}
print("---")
let properties = class_copyPropertyList(cls, &count)!
for i in 0..<count {
let property = properties[Int(i)]
let name = property_getName(property)
print(String(cString: name))
}
That will print a list of all the ivars and properties, which are most of what setValue(_:forKey:)
can access by default on the current class. It won't include properties from the superclass or non-property accessors. You'd have to deeper for that. (But again, this isn't how setValue(_:forKey:)
is used. You use it by reading the documentation for the class, not just poking around.
Using class-dump, you'd see the following for UIActivityViewController
:
class-dump -C '^UIActivityViewController$' /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/PrivateFrameworks/UIKitCore.framework/UIKitCore
///// ... HEADER OMITTED ....
//
// File: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/PrivateFrameworks/UIKitCore.framework/UIKitCore
// UUID: 2DB941E0-513E-3750-9278-C8AFB85CB3C0
//
// Arch: x86_64
// Current version: 61000.0.0
// Compatibility version: 1.0.0
// Source version: 3698.29.8.0.0
//
// Objective-C Garbage Collection: Unsupported
//
@interface UIActivityViewController : UIViewController <UIAlertControllerContaining, UIAlertControllerVisualStyleProviding, UIViewControllerRestoration, UIActionSheetPresentationControllerDelegate, _UIActivityHelperDelegate, _UIShareExtensionHost>
{
_Bool _waitingForInitialShareServicePreferredContentSize;
_Bool _shareServicePreferredContentSizeIsValid;
_Bool __viewServiceBeganConnecting;
_Bool _dismissalDetectionOfViewControllerForSelectedActivityShouldAutoCancel;
_Bool _willDismissActivityViewController;
_Bool _performActivityForStateRestoration;
_Bool _shouldMatchOnlyUserElectedExtensions;
_Bool _hasPerformedInitialPresentation;
_Bool _isPerformingPresentation;
_Bool _allowsEmbedding;
_Bool _showKeyboardAutomatically;
_Bool _sourceIsManaged;
CDUnknownBlockType _completionHandler;
CDUnknownBlockType _completionWithItemsHandler;
NSArray *_excludedActivityTypes;
_UIShareExtensionRemoteViewController *_remoteContentViewController;
NSExtension *_shareExtension;
id <NSCopying> _extensionRequestIdentifier;
id <_UIShareExtensionService> _shareExtensionService;
UISUIActivityViewControllerConfiguration *_activityViewControllerConfiguration;
_UIActivityGroupListViewController *_placeholderViewController;
NSArray *_activityItems;
NSArray *_applicationActivities;
NSMutableDictionary *_activitiesByUUID;
_UIActivityHelper *_activityHelper;
long long _originalPopoverBackgroundStyle;
Class _originalPopoverBackgroundViewClass;
CDUnknownBlockType __popoverDismissalAction;
CDUnknownBlockType _activityPresentationCompletionHandler;
UIAlertController *_activityAlertController;
_UIAlertControllerShimPresenter *_activityAlertControllerShimPresenter;
UIAlertAction *_activityAlertCancelAction;
NSArray *_activityItemProviderOperations;
NSOperationQueue *_activityItemProviderOperationQueue;
long long _totalProviderCount;
long long _completedProviderCount;
unsigned long long _backgroundTaskIdentifier;
NSString *_subject;
unsigned long long _clientAttemptedInitialPresentationOrEmbeddingTimestamp;
unsigned long long _beginPerformingActivityTimestamp;
unsigned long long _viewWillAppearTimestamp;
unsigned long long _readyToInteractTimestamp;
NSArray *_activityTypesToCreateInShareService;
NSArray *_resolvedActivityItemsForCurrentActivity;
CDUnknownBlockType _shareSheetReadyToInteractHandler;
CDUnknownBlockType _preCompletionHandler;
NSArray *_includedActivityTypes;
long long _excludedActivityCategories;
NSArray *_activityTypeOrder;
UIActivity *_activity;
UIViewController *_activityViewController;
id <UIActivityViewControllerDelegate> _airDropDelegate;
}
+ (id)viewControllerWithRestorationIdentifierPath:(id)arg1 coder:(id)arg2;
+ (double)_asyncPresentationTimeout;
+ (_Bool)_popoverPresentationUsesModernPresentation;
+ (_Bool)_usesActionSheetPresentationController;
@property(nonatomic) __weak id <UIActivityViewControllerDelegate> airDropDelegate; // @synthesize airDropDelegate=_airDropDelegate;
@property(retain, nonatomic) UIViewController *activityViewController; // @synthesize activityViewController=_activityViewController;
@property(retain, nonatomic) UIActivity *activity; // @synthesize activity=_activity;
@property(nonatomic) _Bool sourceIsManaged; // @synthesize sourceIsManaged=_sourceIsManaged;
@property(nonatomic) _Bool showKeyboardAutomatically; // @synthesize showKeyboardAutomatically=_showKeyboardAutomatically;
@property(nonatomic) _Bool allowsEmbedding; // @synthesize allowsEmbedding=_allowsEmbedding;
@property(copy, nonatomic) NSArray *activityTypeOrder; // @synthesize activityTypeOrder=_activityTypeOrder;
@property(nonatomic) long long excludedActivityCategories; // @synthesize excludedActivityCategories=_excludedActivityCategories;
@property(copy, nonatomic) NSArray *includedActivityTypes; // @synthesize includedActivityTypes=_includedActivityTypes;
@property(copy, nonatomic) CDUnknownBlockType preCompletionHandler; // @synthesize preCompletionHandler=_preCompletionHandler;
@property(copy, nonatomic, getter=_shareSheetReadyToInteractHandler, setter=_setShareSheetReadyToInteractHandler:) CDUnknownBlockType shareSheetReadyToInteractHandler; // @synthesize shareSheetReadyToInteractHandler=_shareSheetReadyToInteractHandler;
@property(readonly, nonatomic) NSArray *resolvedActivityItemsForCurrentActivity; // @synthesize resolvedActivityItemsForCurrentActivity=_resolvedActivityItemsForCurrentActivity;
@property(retain, nonatomic) NSArray *activityTypesToCreateInShareService; // @synthesize activityTypesToCreateInShareService=_activityTypesToCreateInShareService;
@property(nonatomic, getter=_readyToInteractTimestamp, setter=_setReadyToInteractTimestamp:) unsigned long long readyToInteractTimestamp; // @synthesize readyToInteractTimestamp=_readyToInteractTimestamp;
@property(nonatomic, getter=_viewWillAppearTimestamp, setter=_setViewWillAppearTimestamp:) unsigned long long viewWillAppearTimestamp; // @synthesize viewWillAppearTimestamp=_viewWillAppearTimestamp;
@property(nonatomic, getter=_beginPerformingActivityTimestamp, setter=_setBeginPerformingActivityTimestamp:) unsigned long long beginPerformingActivityTimestamp; // @synthesize beginPerformingActivityTimestamp=_beginPerformingActivityTimestamp;
@property(nonatomic, getter=_clientAttemptedInitialPresentationOrEmbeddingTimestamp, setter=_setClientAttemptedInitialPresentationOrEmbeddingTimestamp:) unsigned long long clientAttemptedInitialPresentationOrEmbeddingTimestamp; // @synthesize clientAttemptedInitialPresentationOrEmbeddingTimestamp=_clientAttemptedInitialPresentationOrEmbeddingTimestamp;
@property(nonatomic, getter=_isPerformingPresentation, setter=_setIsPerformingPresentation:) _Bool isPerformingPresentation; // @synthesize isPerformingPresentation=_isPerformingPresentation;
@property(nonatomic, getter=_hasPerformedInitialPresentation, setter=_setHasPerformedInitialPresentation:) _Bool hasPerformedInitialPresentation; // @synthesize hasPerformedInitialPresentation=_hasPerformedInitialPresentation;
@property(nonatomic) _Bool shouldMatchOnlyUserElectedExtensions; // @synthesize shouldMatchOnlyUserElectedExtensions=_shouldMatchOnlyUserElectedExtensions;
@property(nonatomic) _Bool performActivityForStateRestoration; // @synthesize performActivityForStateRestoration=_performActivityForStateRestoration;
@property(copy, nonatomic) NSString *subject; // @synthesize subject=_subject;
@property(nonatomic) unsigned long long backgroundTaskIdentifier; // @synthesize backgroundTaskIdentifier=_backgroundTaskIdentifier;
@property(nonatomic) long long completedProviderCount; // @synthesize completedProviderCount=_completedProviderCount;
@property(nonatomic) long long totalProviderCount; // @synthesize totalProviderCount=_totalProviderCount;
@property(retain, nonatomic) NSOperationQueue *activityItemProviderOperationQueue; // @synthesize activityItemProviderOperationQueue=_activityItemProviderOperationQueue;
@property(retain, nonatomic) NSArray *activityItemProviderOperations; // @synthesize activityItemProviderOperations=_activityItemProviderOperations;
@property(retain, nonatomic) UIAlertAction *activityAlertCancelAction; // @synthesize activityAlertCancelAction=_activityAlertCancelAction;
@property(retain, nonatomic) _UIAlertControllerShimPresenter *activityAlertControllerShimPresenter; // @synthesize activityAlertControllerShimPresenter=_activityAlertControllerShimPresenter;
@property(retain, nonatomic) UIAlertController *activityAlertController; // @synthesize activityAlertController=_activityAlertController;
@property(copy, nonatomic, getter=_activityPresentationCompletionHandler, setter=_setActivityPresentationCompletionHandler:) CDUnknownBlockType activityPresentationCompletionHandler; // @synthesize activityPresentationCompletionHandler=_activityPresentationCompletionHandler;
@property(nonatomic) _Bool willDismissActivityViewController; // @synthesize willDismissActivityViewController=_willDismissActivityViewController;
@property(nonatomic) _Bool dismissalDetectionOfViewControllerForSelectedActivityShouldAutoCancel; // @synthesize dismissalDetectionOfViewControllerForSelectedActivityShouldAutoCancel=_dismissalDetectionOfViewControllerForSelectedActivityShouldAutoCancel;
@property(copy, nonatomic) CDUnknownBlockType _popoverDismissalAction; // @synthesize _popoverDismissalAction=__popoverDismissalAction;
@property(retain, nonatomic) Class originalPopoverBackgroundViewClass; // @synthesize originalPopoverBackgroundViewClass=_originalPopoverBackgroundViewClass;
@property(nonatomic) long long originalPopoverBackgroundStyle; // @synthesize originalPopoverBackgroundStyle=_originalPopoverBackgroundStyle;
@property(retain, nonatomic) _UIActivityHelper *activityHelper; // @synthesize activityHelper=_activityHelper;
@property(retain, nonatomic) NSMutableDictionary *activitiesByUUID; // @synthesize activitiesByUUID=_activitiesByUUID;
@property(copy, nonatomic) NSArray *applicationActivities; // @synthesize applicationActivities=_applicationActivities;
@property(copy, nonatomic) NSArray *activityItems; // @synthesize activityItems=_activityItems;
@property(retain, nonatomic, getter=_placeholderViewController, setter=_setPlaceholderViewController:) _UIActivityGroupListViewController *placeholderViewController; // @synthesize placeholderViewController=_placeholderViewController;
@property(nonatomic) _Bool _viewServiceBeganConnecting; // @synthesize _viewServiceBeganConnecting=__viewServiceBeganConnecting;
@property(nonatomic) _Bool shareServicePreferredContentSizeIsValid; // @synthesize shareServicePreferredContentSizeIsValid=_shareServicePreferredContentSizeIsValid;
@property(nonatomic) _Bool waitingForInitialShareServicePreferredContentSize; // @synthesize waitingForInitialShareServicePreferredContentSize=_waitingForInitialShareServicePreferredContentSize;
@property(retain, nonatomic) UISUIActivityViewControllerConfiguration *activityViewControllerConfiguration; // @synthesize activityViewControllerConfiguration=_activityViewControllerConfiguration;
@property(retain, nonatomic) id <_UIShareExtensionService> shareExtensionService; // @synthesize shareExtensionService=_shareExtensionService;
@property(copy, nonatomic) id <NSCopying> extensionRequestIdentifier; // @synthesize extensionRequestIdentifier=_extensionRequestIdentifier;
@property(retain, nonatomic) NSExtension *shareExtension; // @synthesize shareExtension=_shareExtension;
@property(retain, nonatomic) _UIShareExtensionRemoteViewController *remoteContentViewController; // @synthesize remoteContentViewController=_remoteContentViewController;
@property(copy, nonatomic) NSArray *excludedActivityTypes; // @synthesize excludedActivityTypes=_excludedActivityTypes;
@property(copy, nonatomic) CDUnknownBlockType completionWithItemsHandler; // @synthesize completionWithItemsHandler=_completionWithItemsHandler;
@property(copy, nonatomic) CDUnknownBlockType completionHandler; // @synthesize completionHandler=_completionHandler;
- (void).cxx_destruct;
- (void)shareExtensionServiceAirDropActivityDidSuccessfullyCompleteTransfer;
- (void)shareExtensionServiceAirDropActivityDidSuccessfullyStartTransfer;
- (void)_willPerformInServiceActivityType:(id)arg1 activitySpecificMetadata:(id)arg2;
- (void)shareExtensionServiceRequestPerformActivityInHostForExtensionActivityWithBundleIdentifier:(id)arg1;
- (void)shareExtensionServiceRequestPerformActivityInHostForActivityUUID:(id)arg1;
- (void)shareExtensionServiceDidFinishPerformingInServiceActivityWithUUID:(id)arg1 responseData:(id)arg2;
- (void)shareExtensionServiceWillPerformInServiceActivityWithDataRequest:(id)arg1 dismissPresentation:(_Bool)arg2 completion:(CDUnknownBlockType)arg3;
- (void)shareExtensionServiceDisableSheetAvoidsKeyboardUntilContentSizeUpdate;
- (void)shareExtensionServiceChangeSheetDismissButtonHidden:(_Bool)arg1;
- (void)shareExtensionServiceChangeSheetDismissButtonTitle:(id)arg1;
- (void)_shareExtensionServicePreferredContentSizeUpdated:(struct CGSize)arg1;
- (_Bool)_shouldShowSystemActivityType:(id)arg1;
- (_Bool)activityHelper:(id)arg1 matchingWithContext:(id)arg2 shouldIncludeSystemActivityType:(id)arg3;
- (id)_configurationForActivity:(id)arg1;
- (id)_activityConfigurationsForActivities:(id)arg1;
- (id)_newShareUIConfigurationWithMatchingResults:(id)arg1;
- (id)_newShareUIConfigurationForCurrentState;
- (void)_loadActivityViewControllerConfiguration;
- (void)_preheatActivityViewControllerConfiguration;
- (void)_insertIntoActivitiesByUUID:(id)arg1;
- (void)_removeFromActivitiesByUUID:(id)arg1;
- (id)_activityWithActivityUUID:(id)arg1;
- (void)decodeRestorableStateWithCoder:(id)arg1;
- (void)encodeRestorableStateWithCoder:(id)arg1;
- (void)actionSheetPresentationControllerDidDismissActionSheet:(id)arg1;
- (id)visualStyleForAlertControllerStyle:(long long)arg1 traitCollection:(id)arg2 descriptor:(id)arg3;
- (void)presentViewController:(id)arg1 animated:(_Bool)arg2 completion:(CDUnknownBlockType)arg3;
- (void)_cancel;
- (void)_didResignContentViewControllerOfPopover:(id)arg1;
- (void)_setPopoverController:(id)arg1;
- (void)observeValueForKeyPath:(id)arg1 ofObject:(id)arg2 change:(id)arg3 context:(void *)arg4;
- (void)_changeActionSheetAvoidsKeyboardDisabledUntilNextUpdatePreferredContentSize:(_Bool)arg1;
- (void)_changeActionPresentationDismissButtonHidden:(_Bool)arg1;
- (void)_changeActionPresentationDismissButtonTitle:(id)arg1;
- (void)_endDismissalDetectionOfViewControllerForSelectedActivityShouldAutoCancel;
- (void)_presentationControllerDismissalTransitionDidEndNotification:(id)arg1;
- (void)_beginDismissalDetectionOfViewControllerForSelectedActivityShouldAutoCancel;
- (void)_endInProgressActivityExecutionForcedStrongReference;
- (void)_beginInProgressActivityExecutionForcedStrongReference;
- (_Bool)_queueBackgroundOperationsForActivityItems:(id)arg1 activityBeingPerformed:(id)arg2;
- (void)_performActivity:(id)arg1;
- (_Bool)_shouldExecuteItemOperation:(id)arg1 forActivity:(id)arg2;
- (void)_performActivityOfType:(id)arg1 executionEnvironment:(long long)arg2;
- (void)_prepareActivity:(id)arg1 completion:(CDUnknownBlockType)arg2;
- (void)_prepareActivity:(id)arg1;
- (id)_titleForActivity:(id)arg1;
- (void)_resetAfterActivity:(_Bool)arg1;
- (void)_executeActivity;
- (void)_cleanupActivityWithSuccess:(_Bool)arg1;
- (void)_cleanupActivityWithSuccess:(_Bool)arg1 items:(id)arg2 error:(id)arg3;
- (void)_emitInteractionTelemetry:(_Bool)arg1 error:(id)arg2;
- (void)_clearActivity;
- (void)_performDismissWithCompletionHandler:(CDUnknownBlockType)arg1;
- (void)_updateSourceIsManagedForURLs;
- (_Bool)shouldAutorotateToInterfaceOrientation:(long long)arg1;
- (void)viewWillTransitionToSize:(struct CGSize)arg1 withTransitionCoordinator:(id)arg2;
- (void)dismissViewControllerAnimated:(_Bool)arg1 completion:(CDUnknownBlockType)arg2;
- (void)setModalPresentationStyle:(long long)arg1;
- (id)_presentationControllerForPresentedController:(id)arg1 presentingController:(id)arg2 sourceController:(id)arg3;
- (_Bool)_requiresCustomPresentationController;
- (void)_updatePlaceholderPreferredContentSize;
- (void)preferredContentSizeDidChangeForChildContentContainer:(id)arg1;
- (void)viewSafeAreaInsetsDidChange;
- (void)viewDidLayoutSubviews;
- (void)__viewControllerWillBePresented:(_Bool)arg1;
- (void)viewWillDisappear:(_Bool)arg1;
- (void)viewDidAppear:(_Bool)arg1;
- (void)viewWillAppear:(_Bool)arg1;
- (double)_displayHeight;
- (void)_presentationOrEmbeddingDidBegin:(_Bool)arg1;
- (void)_createAndInstallPlaceholderViewControllerIfNeeded;
- (_Bool)_isActionRowExcluded;
- (_Bool)_isSharingRowExcluded;
- (_Bool)_isAirDropExcludedWithActivityItemValues:(id)arg1;
- (_Bool)_shouldIncludeTagsUIPlaceholderWithActivityItemValues:(id)arg1;
- (id)_containedAlertController;
- (void)_shareSheetReadyToInteractAfterCACommit:(_Bool)arg1;
- (void)_removePlaceholderViewControllerIfNeeded;
- (void)_installViewController:(id)arg1;
- (void)_embedRemoteContentViewControllerAndPerformAfterCompletingFencedCommit:(CDUnknownBlockType)arg1;
- (void)viewDidLoad;
- (void)_updateActivityViewControllerConfiguration;
- (void)_updateActivityItems:(id)arg1;
- (id)_newActivityMatchingContext;
- (id)_availableActivities;
- (id)_activityItemValues;
- (id)_securityScopedURLsForMatching;
- (id)_activityItemURLValuesForMatching;
- (id)_placeholderActivityItemValues;
- (void)dealloc;
- (void)_setupLegacyAlertPresentationControllers;
- (void)_preheatActivitiesIfNeeded;
- (void)_shareServiceFinishedInitialPreferredContentSizeUpdate;
- (void)_sendInitialShareServiceConfigurationAndUpdatePreferredContentSize;
- (void)_retryRemoteViewServiceConnectionIfPossibleWithPriming:(_Bool)arg1 previousAttempts:(long long)arg2;
- (void)_connectToRemoteViewServiceOnceWithPriming:(_Bool)arg1 previousAttempts:(long long)arg2;
- (void)_primeExtensionDiscovery;
- (void)_preloadInitialConfigurationLocallyIfNeeded;
- (id)initWithActivityItems:(id)arg1 applicationActivities:(id)arg2;
- (id)initWithCoder:(id)arg1;
- (id)initWithNibName:(id)arg1 bundle:(id)arg2;
- (id)init;
@property(copy, nonatomic) CDUnknownBlockType dismissCompletionHandler;
// Remaining properties
@property(readonly, copy) NSString *debugDescription;
@property(readonly, copy) NSString *description;
@property(readonly) unsigned long long hash;
@property(readonly) Class superclass;
@end
But again, this is only for exploration. You should never rely on this information for production code. (For example, the version of UIKitCore in /System/iOSSupport/System/Library/PrivateFrameworks/ has a smaller list of ivars that doesn't include subject
, so this may not even work on all UIKit platforms.)
Unrelated note: the actual property's name is subject
, not Subject
. You're getting away with this because setValue(_:forKey:)
capitalizes the first letter automatically and constructs setSubject:
. See the Key-Value Coding Programming Guide for more details about how this works. Generally speaking, KVC is not as commonly used directly in Swift, and setValue(_:forKey:)
and other KVC methods should generally be avoided in Swift unless you know what you're doing. They're not type-safe.