Fix memory leak where swapchains and images were not destroyed due to a retention loop.

Add Cube app iOS device rotation support, to test swapchain destruction on iOS.
diff --git a/Demos/Cube/iOS/DemoViewController.m b/Demos/Cube/iOS/DemoViewController.m
index 2edf35c..d0b272c 100644
--- a/Demos/Cube/iOS/DemoViewController.m
+++ b/Demos/Cube/iOS/DemoViewController.m
@@ -62,6 +62,12 @@
 	demo_draw(&demo);
 }
 
+// Allow device rotation to resize the swapchain
+-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator {
+	[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
+	demo_resize(&demo);
+}
+
 @end
 
 
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index 2b2bb2c..250455a 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -22,6 +22,7 @@
 - Always explicitly set `CAMetalLayer` colorspace property based on _Vulkan_ parameters, 
   and don't rely on _Metal_ default values.
 - Avoid use of _Metal_ renderpass load and store actions on memoryless attachments.
+- Fix memory leak on swapchain destruction.
 - Remove project qualifiers from references to `SPIRV-Cross` header files.
 - `MVKDescriptorPool` pools its descriptor sets.
 - Enable `MVKConfiguration::preallocateDescriptors` and `MVK_CONFIG_PREALLOCATE_DESCRIPTORS` 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h
index e00b73c..051db4c 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h
@@ -97,6 +97,8 @@
 	/** VK_GOOGLE_display_timing - returns past presentation times */
 	VkResult getPastPresentationTiming(uint32_t *pCount, VkPastPresentationTimingGOOGLE *pPresentationTimings);
 	
+	void destroy() override;
+
 #pragma mark Construction
 	
 	MVKSwapchain(MVKDevice* device, const VkSwapchainCreateInfoKHR* pCreateInfo);
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm
index 6f834a8..012d753 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm
@@ -464,9 +464,16 @@
 	_presentHistoryIndex = (_presentHistoryIndex + 1) % kMaxPresentationHistory;
 }
 
-MVKSwapchain::~MVKSwapchain() {
+// A retention loop exists between the swapchain and its images. The swapchain images
+// retain the swapchain because they can be in flight when the app destroys the swapchain.
+// Release the images now, when the app destroys the swapchain, so they will be destroyed when
+// no longer held by the presentation flow, and will in turn release the swapchain for destruction.
+void MVKSwapchain::destroy() {
 	for (auto& img : _presentableImages) { _device->destroyPresentableSwapchainImage(img, NULL); }
+	MVKVulkanAPIDeviceObject::destroy();
+}
 
+MVKSwapchain::~MVKSwapchain() {
     if (_licenseWatermark) { _licenseWatermark->destroy(); }
     [this->_layerObserver release];
 }