Drag & Drop in your iOS applications

 3r3447. 3r3-31. Drag & Drop in your iOS applications Drag & Drop working in iOS 11 3r340346. and 3r340405. iOS 12 3r340346. , Is a method of graphical asynchronous copying or movement of data both within one application and between different applications. Although this technology is about 30 years old, it has literally become a “breakthrough” technology on 3r340405. iOS 3r334406. due to the fact that when you drag something into iOS 3r334406. , 3r340345. multitouch allows you to freely interact with the rest of the system and collect data to reset from different applications. 3r34415.  3r3447. 3r34034. 3r34415.  3r3447. 3r340405. iOS 3r334406. makes it possible to capture multiple items at once. And they do not have to be in convenient accessibility for selection: you can take the first object, then go to another application and grab something else - all the objects will be collected in a “stack” under your finger. Then call the universal dock on the screen, open any application there and grab the third object, and then go to the screen with applications running and, without releasing the objects, drop them into one of the open programs. This freedom of action is possible on iPad , at 3r34034. iPhone 3r334346. coverage area. Drag & Drop in 3r340405. iOS 3r334406. limited to a single application. 3r34415.  3r3447. 3r34415.  3r3447. Most popular applications ( Safary , Chrome , 3r3-34405. IbisPaint X Art. 3rr.3405. Mail 3r340405. Drag & Drop . In addition to this, Apple put at the disposal of the developers a very simple and intuitive 3r340405. API 3r340346. for embedding mechanism Drag & Drop in your application. Mechanism Drag & Drop just like gestures, works on UIView 3r344410. and uses the concept of "interactions" 3r34407. Interactions 3r3434393. 3r344410. , a bit like gestures, so you can think about the mechanism of Drag & Drop just like a really powerful gesture. 3r34415.  3r3447. 3r34415.  3r3447. It, as well as gestures, is very easy to integrate into your application. Especially if your application uses the table. UITableView 3r344410. or a collection of UICollectionView 3r344410. , because for them API Drag & Drop improved and raised to a higher level of abstraction in the sense that the collection 3r-34405. Collection View helps you with r3r34407. indexPath 3r344410. the collection item you want to drag Drag . She knows where your finger is and interprets it as 3r340347. indexPath 3r344410. collection item that you drag Drag at the moment or as [b] indexPath 3r344410. element of the collection where you “drop” 3r34405. Drop something. So the collection. Collection View provides you with [b] indexPath 3r344410. but otherwise it is absolutely the same API Drag & Drop as for the usual [b] UIView 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. Process 3r340405. Drag & Drop on 3r340405. iOS 3r334406. It has 4 different phases:
 3r3447. 3r34415.  3r3447. 3r3197. Lift 3r3198. 3r34415.  3r3447. 3r340347. Lift
(lift) is when the user performs a gesture 3r333333. long press
3r344410. , specifying an element that will be “dragged and dropped.” At this moment, a very lightweight so-called “preview” (3r-34405. Lift preview 3r-34406.) Of the specified element is formed, and then the user begins to move (3r?43?405. Dragging 3r-34406.) His fingers. 3r34415.  3r3447. 3r34415.  3r3447. 3r3147. 3r34415.  3r3447. 3r34415.  3r3447. 3r3197. Drag (drag) 3r34415.  3r3447. 3r340347. Drag (drag and drop) is when the user moves the object along the surface of the screen. During this “preview” phase (3r334345. Lift preview ) For this object it can be modified (a green plus sign "+" or another sign appears) 3r34415.  3r3447. 3r34415.  3r3447. 3r3164. 3r34415.  3r3447. 3r34415.  3r3447. some interaction with the system is also allowed: you can click on some other object and add it to the current drag-and-drop session: 3r34415.  3r3447. 3r34415.  3r3447. 3r3173. 3r34415.  3r3447. 3r34415.  3r3447. 3r3197. Drop (drop) 3r34415.  3r3447. 3r340347. Drop (dropping) occurs when the user lifts a finger. At this point, two things can happen: either Drag the object will be destroyed, or a “reset” 3r34405 will occur. Drop object at destination. 3r34415.  3r3447. 3r34415.  3r3447. 3r3192. 3r34415.  3r3447. 3r34415.  3r3447. 3r3197. Data Transfer 3r3198. 3r34415.  3r3447. If the process of "dragging" Drag it was not canceled and a “reset” 3r34407 took place. Drop
then happens Data Transfer (data transfer), in which the “reset point” requests data from the “source”, and asynchronous data transfer occurs. 3r34415.  3r3447. 3r34415.  3r3447. This tutorial is based on the example of the “Image Gallery” demo application, borrowed from 3-33594. From the homework of the Stanford course CS193P , we show how easy it is to implement the mechanism. Drag & Drop in your iOS 3r334406. attachment. 3r34415.  3r3447. We will endow the collection. Collection View the ability to fill oneself with images from outside, as well as to reorganize the elements INSIDE yourself with the help of the mechanism 3r34405. Drag & Drop . In addition, this mechanism will be used to reset unnecessary elements of the collection. Collection View in the "trash can", which is the usual UIView 3r344410. and represented by a button on the navigation bar. We can also share through the mechanism. Drag & Drop images collected in our Gallery from other applications, for example, with “Notes” (3r340405. Notes 3r334406. or 3r.334405. Notability 3r340346.) or by mail 3r340345. Mail 3r340346. or with a photo library ( Photo ). 3r34415.  3r3447. 3r34415.  3r3447. But before focusing on the implementation of the mechanism 3r34405. Drag & Drop to the “Gallery of Images” demo application, I will walk very briefly through its main components. 3r34415.  3r3447. 3r34415.  3r3447. 3r3436969. Features of the “Image Gallery” demo application 3r3434370. 3r34415.  3r3447. The user interface (3r334405. UI 3r3-34406.) Of the Image Gallery application is very simple. This is the “screen fragment” Image Gallery Collection View Controller inserted in Navigation Controller : 3r344415.  3r3447. 3r34415.  3r3447. which is supported by the class [b] ImageGalleryCollectionViewController 3r344410. with the Image Gallery Model as a variable 3-3334407. var imageGallery = ImageGallery () 3r3434393. 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. struct ImageGallery 3r344410. containing an array of images [b] images 3r344410. in which each image is described by the structure [b] struct ImageModel 3r344410. containing URL 3r340346. 3r340347. url 3r344410. image locations (we are not going to store the image itself) and its aspect ratio [b] aspectRatio 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r33333. 3r34415.  3r3447. 3r34415.  3r3447. Our [b] ImageGalleryCollectionViewController 3r344410. implements [b] DataSource 3r344410. protocol: 3r34415.  3r3447. 3r34415.  3r3447. 3r33333. 3r34415.  3r3447. 3r34415.  3r3447. Custom cell collection [b] cell 3r344410. Contains image 3r340347. imageView: UIImageView! 3r3439393 3r344410. and activity indicator 3r340407. spinner: UIActivityIndicatorView! 3r3439393 3r344410. and is supported by a custom subclass 3r340347. ImageCollectionViewCell 3r344410. class [b] UICollectionViewCell 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r33333. 3r34415.  3r3447. 3r34415.  3r3447. 3r340405. Public API 3r340406. class [b] ImageCollectionViewCell 3r344410. - this is URL 3r340346. images [b] imageURL 3r344410. . As soon as we install it, our UI updated, that is, asynchronously selects the data for the image on this [b] imageURL 3r344410. and displayed in a cell. While data is being retrieved from the network, the activity indicator 3r34407 is working. spinner 3r344410. , showing that we are in the process of sampling data. 3r34415.  3r3447. 3r34415.  3r3447. I use to get data for a given URL 3r340346. global lineup [b] global (qos: .userInitiated) 3r344410. with the “quality of service” argument 3r340407. qos 3r344410. which is set to [b] .userInitiated 3r344410. because I select the data requested by the user: 3r344415.  3r3447. 3r34415.  3r3447. 3r33410. 3r34415.  3r3447. 3r34415.  3r3447. Every time you use your own variables inside the closure, in our case it is [b] imageView 3r344410. and 3r340347. imageURL 3r344410. , the compiler forces you to put in front of them [b] self. 3r3439393 3r344410. so you ask yourself: “Isn’t there a“ cyclic memory reference ”(3r34405. memory cycle 3r34034.)?” We do not have an explicit “cyclic memory reference” here (3r340405. memory cycle 3rr34406.), because 3r340347. self 3r344410. There is no pointer to this closure. 3r34415.  3r3447. 3r34415.  3r3447. However, in the case of multithreading, you must take into account that the cells are 3r-34407. cells 3r344410. in collection 3r340405. Collection View are reusable thanks to the [b] method. dequeueReusableCell 3r344410. . Each time a cell (new or re-used) hits the screen, the image is launched asynchronously from the network (at this time the “wheel” of the activity indicator is spinning 3r340407. 3r34392. Spinner 3r34393. 3r34410.). 3r34415.  3r3447. 3r34415.  3r3447. Once the download is complete and the image is received, is updated. UI this cell collection. But we don’t wait for the image to load, we continue to scroll through the collection and the collection cell that we notice goes off the screen without updating our 3r340405. UI . However, a new image should appear from below, and the same cell that has left the screen will be reused, but for another image, which may load quickly and update UI . At this time, the image download previously started in this cell will return and the screen will be updated, which will lead to an incorrect result. This is because we are running different things working on the network in different threads. They return at different times. 3r34415.  3r3447. 3r34415.  3r3447. How can we fix the situation? 3r34415.  3r3447. Within the limits of the mechanism used by us [b] GCD 3r344410. we cannot cancel the loading of an image of a cell that has left the screen, but we can, when our data comes from the network, 3r340407. imageData 3r344410. , check out URL 3r340346. 3r340347. url 3r344410. , which caused the download of this data, and compare it with the one that the user wants to have in this cell at the moment, thenbe 3r340347. imageURL 3r344410. . If they do not match, then we will not update 3r334405. UI cell and wait for the image data we need:
 3r3447. 3r34415.  3r3447. url == self.imageURL 3r344410. makes everything work properly in a multithreaded environment that requires non-standard imagination. The fact is that some things in multithreaded programming occur in a different order than the written code. 3r34415.  3r3447. 3r34415.  3r3447. If the image data could not be sampled, an image is generated with an error message in the form of an “Error” string and an emoji with a frowning face. Just empty space in our collection. Collection View may confuse the user a little:
 3r3447. 3r34415.  3r3447. 3r33512. 3r34415.  3r3447. 3r34415.  3r3447. We would not like the image with the error message to repeat [b] aspectRatio 3r344410. of this erroneous image, because in this case the text along with Emodzhi will stretch or shrink. We would like it to be neutral - square, that is, it would have an aspect ratio of 3r-34407. aspectRatio 3r344410. close to 1.0. 3r34415.  3r3447. 3r34415.  3r3447. 3r? 3529. 3r34415.  3r3447. 3r34415.  3r3447. We have to communicate this wish to our Controller , so he fixed in his Model [b] imageGallery 3r344410. aspect ratio [b] aspectRatio 3r344410. for the corresponding 3r340407. indexPath 3r344410. . This is an interesting task, there are many ways to solve it, and we will choose the easiest of them - use 3r340347. Optional 3r344410. closures ( closure ) [b] var changeAspectRatio: (() -> Void)? 3r3439393 3r344410. . It can be [b] nil 3r3439393. 3r344410. and it does not need to be installed if it is not necessary: ​​
 3r3447. 3r34415.  3r3447. 3r3566. 3r34415.  3r3447. 3r34415.  3r3447. When you call a closure [b] changeAspectRatio? () 3r344410. in the case of an erroneous sample of data, I use the [b] chain. Optional 3r344410. . Now anyone who is interested in some kind of setting when receiving an erroneous image can set this closure to something concrete. And that is what we are doing in our Controller in method 3r340407. cellForItemAt 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r3-3589. 3r34415.  3r3447. 3r34415.  3r3447. Details can be found 3r3r94. here is . 3r34415.  3r3447. 3r34415.  3r3447. To display images with the correct [b] aspectRatio 3r344410. [b] method is used. sizeForItemAt 3r344410. delegate 3r340347. UICollectionViewDelegateFlowLayout 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r31616. 3r34415.  3r3447. 3r34415.  3r3447. In addition to the image collection Collection View , on our UI we placed a button on the navigation panel 3r34034. Bar Button
with a custom image [b] GarbageView 3r3439393. 3r344410. containing a “trash can” as 3r340347. subview 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. itself have been specifically changed. GarbageView 3r3439393. 3r344410. and buttons 3r340347. UIButton 3r344410. with the image of a "trash can" (in fact, there is a transparent background) so that you can see that the user who "dumps" the Gallery's images into the "trash can" has much more room for maneuver when "resetting" 3rr34407. Drop
than just a garbage can icon. 3r34415.  3r3447. In the class GarbageView 3r3439393. 3r344410. two initializers and both use the [b] method. setup () 3r3434393. 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r3668. 3r34415.  3r3447. 3r34415.  3r3447. In method 3r340347. setup () 3r3434393. 3r344410. I also add as [b] subview button. myButton 3r344410. with the image of a “trash can” taken from a standard Bar Button buttons. Trash : 3r344415.  3r3447. 3r34415.  3r3447. GarbageView 3r3439393. 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r3704. 3r34415.  3r3447. 3r34415.  3r3447. The size of the “trash can” and its location will be determined in method [b] layoutSubviews () 3r344410. class [b] UIView 3r344410. depending on the boundaries [b] bounds 3r344410. This [b] UIView 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r340346. 3r344410. in the folder 3r33825. 3r340405. ImageGallery_beginning 3r33838. . If you launch this version of the Image Gallery application, you will see the result of the application’s work on the test data, which we will subsequently delete and fill in the Image Gallery only OTHER: 3r34415.  3r3447. 3r34415.  3r3447. 3r33748. 3r34415.  3r3447. 3r34415.  3r3447. The plan for the implementation of the mechanism 3r340405. Drag & Drop Our application consists of the following: 3r344415.  3r3447. 3r34415.  3r3447. 3r3759.  3r3447. First, we will endow our collection of images Collection View the ability to "drag" 3r340345. Drag From her image [b] UIImage 3r344410. both externally and locally,  3r3447. then we will teach our image collection Collection View take the “tied” 3r340345. Drag outside or locally images [b] UIImage 3r344410. ,  3r3447. we will also teach our [b] GarbageView 3r3439393. 3r344410. With the “trash can” button, take “tightened” from the local collection Collection View images [b] UIImage 3r344410. and remove them from the collection. Collection View  3r3447. 3r34415.  3r3447. 3r34415.  3r3447. If you go through to the end of this tutorial and make all the necessary code changes, you will receive the final version of the “Image Gallery” demo application, which incorporates the 3r340405 mechanism. Drag & Drop . She is on r3r34407. 3r340405. 3r34034. Github 3r340346. 3r344410. in the folder 3r33825. 3r340405. ImageGallery_finished 3r33838. . 3r34415.  3r3447. 3r34415.  3r3447. The efficiency of the mechanism Drag & Drop in your collection Collection View provided by two new delegates. 3r34415.  3r3447. Methods [u] first delegate, 3r340347. dragDelegate 3r344410. , 3r33830. configured to initialize and customize the “drag and drop” 3r-34405. Drags . 3r34415.  3r3447. Methods 3r3-3835. dropDelegate 3r344410. , complete the "drag and drop" Drags and, in general, provide data transfer (3r334405. Data transfer ) and custom animation settings when “resetting” 3r340405. Drop , as well as other similar things. 3r34415.  3r3447. 3r34415.  3r3447. It is important to note that both of these protocols are completely independent. You can use one or the other protocol if you only need to “tug” 3r-34405. Drag or just "reset" Drop , but you can use both protocols at once and carry out simultaneously “pulling” 3r-34405. Drag , and the “reset” Drop that opens up additional functionality of the mechanism. Drag & Drop by reordering the items in your collection. Collection View . 3r34415.  3r3447. 3r34415.  3r3447. 3r3436969. Drag and drop Drag elements of the collection Collection View 3r34370. 3r34415.  3r3447. Implement Drag the protocol is very simple, and the first thing you should always do is install yourself, [b] self 3r344410. , as delegate to [b] dragDelegate 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r3887. 3r34415.  3r3447. 3r34415.  3r3447. And, of course, at the very top of the class [b] ImageGalleryCollectionViewController 3r344410. you should say yes, we implement the 3r334407 protocol. UICollectionViewDragDelegate 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r3904. 3r34415.  3r3447. 3r34415.  3r3447. As soon as we do this, the compiler starts to “complain”, we click on the red circle and we are asked: “Do you want to add the required protocol methods 3r34407. UICollectionViewDragDelegate 3r344410. ? ”3r34415.  3r3447. I answer: “Of course I want!” And click on the button Fix : 3r344415.  3r3447. 3r34415.  3r3447. 3r33921. 3r34415.  3r3447. 3r34415.  3r3447. The only required protocol method is [b] UICollectionViewDragDelegate 3r344410. is method [b] itemsForBeginning 3r344410. who will say Drag the system that we are dragging. Method [b] itemsForBeginning 3r344410. invoked when a user starts dragging (3r340405. Dragging 3r340406.) a cell of the collection 3r340407. cell 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. Notice that this method has a collection. Collection View added [b] indexPath 3r344410. . This will tell us which item is in the collection, which is [b] indexPath 3r344410. we're going to drag. For us, this is really very convenient, since it is up to the application to be responsible for the use of arguments 3r-34407. session 3r344410. and 3r340347. indexPath 3r344410. to figure out how to handle this “dragging” Drag . 3r34415.  3r3447. 3r34415.  3r3447. If an array of 3r340347 is returned. [UIDragItems]3r3439393 3r344410. “Overtightened” elements, then “pulling” Drag initialized if an empty [b] array is returned. []3r3439393 3r344410. then “pulling” Drag ignored. 3r34415.  3r3447. 3r34415.  3r3447. I will create a small [b] private 3r344410. function [b] dragItems (at: indexPath) 3r344410. with the argument [b] indexPath 3r344410. . It returns the array we need [b] [UIDragItem]3r3439393 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. looks like. UIDragItem 3r344410. ? 3r34415.  3r3447. He has only one very IMPORTANT thing, which is called [b] itemProvider 3r344410. . 3r340347. itemProvider 3r344410. - it's just something that can provide data that will be dragged. 3r34415.  3r3447. 3r34415.  3r3447. And you have the right to ask: “And what about the“ dragging ”of the element 3r34407. UIDragItem 3r344410. which simply has no data? ”The item you want to drag may not have data, for example, becausethat the creation of this data is a costly operation. This may be an image [b] image 3r344410. or something that requires downloading data from the internet. Remarkably, operation Drag & Drop is completely asynchronous. When you start drag and drop Drag then it’s really a very lightweight object (3r334345. lift preview ), you drag it around, and nothing happens during this “drag and drop”. But as soon as you “throw” Drop somewhere your object, then he, being [b] itemProvider 3r344410. , really has to provide your “dragged” and “dropped” object with real data, even if it takes a certain amount of time. 3r34415.  3r3447. 3r34415.  3r3447. Fortunately, there are many built-in [b] itemProviders 3r344410. . These are the classes that already exist in iOS 3r334406. and which are 3r340347. itemPoviders 3r344410. , such as, for example, NSString which allows you to drag text without fonts. Of course, this image is [b] UIImage 3r344410. . You can select and drag [b] images all over the place. UIImages 3r344410. . Class [b] NSURL 3r3434393. 3r344410. that is absolutely wonderful. You can go to Web 3r340346. page, select URL 3r340346. and “throw” him wherever you want. This may be a link to the article or URL 3r340346. for an image like this in our demo. These are the color classes [b] UIColor 3r344410. , map element [b] MKMapItem 3r344410. , contact [b] CNContact 3r344410. from the address book, a lot of things you can choose and “drag”. All of them are [b] itemProviders 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. We're going to drag the image [b] UIImage 3r344410. . It is located in the cell of the collection. Collection View from 3r340347. indexPath 3r344410. which helps me to select the cell [b] cell 3r344410. , get out of it Outlet 3r340347. imageView 3r344410. and get his image [b] image 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. Let's express this idea in a couple of lines of code. 3r34415.  3r3447. First I request my collection Collection View o cell [b] cell 3r344410. for the element 3r340347. item 3r344410. corresponding to this 3r340407. indexPath 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. 3r31155. 3r34415.  3r3447. 3r34415.  3r3447. Method [b] cellForItem (at: IndexPath) 3r344410. for the collection. Collection View It works only for visible ( visible ) cells, but, of course, it will work in our case, because I am “dragging” 3r340405. Drag element of the collection, which is on the screen, and it is visible. 3r34415.  3r3447. 3r34415.  3r3447. So, I received a “drag and drop” cell 3r334407. cell 3r344410. . 3r34415.  3r3447. Next, I apply the [b] operator. as? 3r3439393 3r344410. to this cell so that it has the TYPE of my custom subclass . And if it works, then I get Outlet 3r340347. imageView 3r344410. , from whom I take his image [b] image 3r344410. . I just “captured” the image [b] image 3r344410. for this [b] indexPath 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. Now that I have an image [b] image 3r344410. , all I need to do is create one of these 3r334347. UIDragItems 3r344410. using the resulting image [b] image 3r344410. as 3r340407. itemProvider 3r344410. , that is, the thing that provides us with data. 3r34415.  3r3447. I can create [b] dragItem 3r344410. using the constructor [b] UIDragItem 3r344410. which takes as an argument [b] itemProvider 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r31242. 3r34415.  3r3447. 3r34415.  3r3447. Then we create [b] itemProvider 3r344410. for the image [b] image 3r344410. also using the [b] designer. NSItemProvider 3r344410. . There are several constructors for [b] NSItemProvider 3r344410. , but among them there is one really remarkable - [b] NSItemProvider (object: NSItemProviderWriting) 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r31271. 3r34415.  3r3447. 3r34415.  3r3447. This designer [b] NSItemProvider 3r344410. you just give the object [b] object 3r344410. and he knows how to make him [b] itemProvider 3r344410. . As such an object [b] object 3r344410. I give the image an image of [b] image 3r344410. I got from cell [b] cell 3r344410. and get 3r340347. itemProvider 3r344410. for [b] UIImage 3r344410. . 3r34415.  3r3447. And it's all. We created 3r340407. dragItem 3r344410. and should return it as an array having one element. 3r34415.  3r3447. 3r34415.  3r3447. But before I return [b] dragItem 3r344410. , I'm going to do one more thing, namely, set the variable [b] localObject 3r344410. for [b] dragItem 3r344410. equal to the resulting image [b] image 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. 3r31338. 3r34415.  3r3447. 3r34415.  3r3447. What does this mean? 3r34415.  3r3447. If you are doing a "drag and drop" Drag locally, that is, inside your application, you do not need to go through all this code associated with [b] itemProvider 3r344410. via asynchronous data retrieval. You do not need to do this, you just need to take [b] localObject 3r344410. and use it. This is a kind of “short circuit” in the local “dragging” 3r34405. Drag . 3r34415.  3r3447. 3r34415.  3r3447. The code we write will work when “dragging” 3r340405. Drag outside of our collection. Collection View to other applications, but if we “drag” Drag locally, then we can use [b] localObject 3r344410. . Next, I return an array consisting of a single element [b] dragItem 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. By the way, if I could not get for some reason [b] image 3r344410. for this cell [b] cell 3r344410. , then I return an empty array [b] []3r3439393 3r344410. This means "dragging" Drag is canceled. 3r34415.  3r3447. 3r34415.  3r3447. localObject 3r344410. , you can remember the local context [b] localContext 3r344410. for our Drag Sessions 3r334407. session 3r344410. . In our case, it will be a [b] collection. collectionView 3r344410. and it will come in handy later: 3r34415.  3r3447. 3r34415.  3r3447. Drag You can add even more elements [b] items 3r344410. to this “drag and drop” by simply performing a gesture [b] 3r333333. tap 3r344410. on them. As a result, you can drag Drag many elements at a time. And this is easy to implement using the other delegate method 3r334407. UICollectionViewDragDelegate 3r344410. , very similar to the [b] method. itemsForVeginning 3r344410. , a method named [b] itemsForAddingTo 3r344410. . Method [b] itemsForAddingTo 3r344410. It looks exactly the same as the [b] method. itemsForVeginning 3r344410. , and returns exactly the same thing, because it also gives us [b] indexPath 3r344410. what the user “tapped” on in the process of “dragging” 3r-34405. Drag and it's enough for me to get the image [b] image 3r344410. from the cell on which the user “tapped” and return it. 3r34415.  3r3447. 3r34415.  3r3447. 3r31475. 3r34415.  3r3447. 3r34415.  3r3447. Return an empty array [b] []3r3439393 3r344410. from method 3r340407. itemsForAddingTo 3r344410. causes gesture [b] 3r333333. tap 3r344410. will be interpreted in the usual way, that is, as the selection of this cell [b] cell 3r344410. . 3r34415.  3r3447. And this is all we need to “drag and drop” Drag . 3r34415.  3r3447. Run the application. 3r34415.  3r3447. I choose the “Venice” image, hold it for a while and start moving 3r34415.  3r3447. 3r34415.  3r3447. 3r? 31508. 3r34415.  3r3447. 3r34415.  3r3447. and we can really drag this image into the app 3r340405. Photos , as you see a green plus sign "+" in the upper left corner of the "drag and drop" image. I can do the gesture [b] 3r333333. tap 3r344410. Another image shows the Artik from the 3-3334405 collection. Collection View
3r34415.  3r3447. 3r34415.  3r3447. 3r31525. 3r34415.  3r3447. 3r34415.  3r3447. and now we can throw two images into the app 3r340405. Photos : 3r344415.  3r3447. 3r34415.  3r3447. 3r31536. 3r34415.  3r3447. 3r34415.  3r3447. Since the application Photos already built mechanism Drag & Drop then everything works fine and it's awesome. 3r34415.  3r3447. So, I work "pulling" 3r334405. Drag and “reset” 3r334405. Drop Images of the Gallery to other applications, I did not have to do much in my application, except for the delivery of the image [b] image 3r344410. as an array [b] [UIDragItem]3r3439393 3r344410. . This is one of the many great features of the mechanism. Drag & Drop - it is very easy to make it work in both directions. 3r34415.  3r3447. 3r34415.  3r3447. 3r3436969. Reset 3r340405. Drop images to the collection. Collection View 3r34370. 3r34415.  3r3447. Now we need to do Drop part for my collection Collection View so that you can “reset” 3r340345. Drop any "drag and drop" images INSIDE this collection. “Dragged” image can “come” both from outside and directly from inside of this collection. 3r34415.  3r3447. To do this, we do the same thing as we did with the delegate 3r340407. dragDelegate 3r344410. , that is, we make ourselves, [b] self 3r344410. delegate 3r340347. dropDelegate 3r344410. in method 3r340407. viewDidLoad 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r31601. 3r34415.  3r3447. 3r34415.  3r3447. We again have to climb to the top of our class 3r340407. ImageGalleryCollectionViewController 3r344410. and confirm the implementation of the protocol 3r340407. UICollectionViewDropDelegate 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r31618. 3r34415.  3r3447. 3r34415.  3r3447. As soon as we added our new protocol, the compiler again began to “complain” that we did not implement this protocol. Click on the button Fix , and before us appear the mandatory methods of this protocol. In this case, we are told that we need to implement the method 3r340407. performDrop 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r31633. 3r34415.  3r3447. 3r34415.  3r3447. We must do this, otherwise there will be no “reset” 3r340405. Drop . In fact, I'm going to implement the [b] method. performDrop 3r344410. last but not least, because there are a couple of other highly recommended 3r340405. Apple methods that need to be implemented for Drop parts. This is [b] canHandle 3r344410. and 3r340347. dropSessionDidUpdate 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r31660. 3r34415.  3r3447. 3r34415.  3r3447. If we implement these two methods, then we can get a small green plus sign “+” when we drag images OUTSIDE onto our collection 3r334405. .  3r3447. 3r34415.  3r3447. Let's implement [b] canHandle 3r344410. . You and I have a version of the method [b] canHandle 3r344410. that targets the collection. Sollection View . But it is this method Sollection View It looks exactly the same as a similar method for the usual [b] UIView 3r344410. , there is no [b] indexPath 3r344410. . We just need to return [b] session.canLoadObjects (ofClass: UIImage.self) 3r344410. , and this means that I accept the “reset” of objects of this class in my collection 3r-34405. Sollection View : 3r344415.  3r3447. 3r34415.  3r3447. 3r31701. 3r34415.  3r3447. 3r34415.  3r3447. But this is not enough for a “reset” 3r34405. Drop images in my collection Collection View Izvne. 3r34415.  3r3447. If the "reset" Drop The image takes place in the collection. Collection View when the user reorganizes their own elements [b] items 3r344410. using the mechanism 3r340345. Drag & Drop , one image is enough [b] UIImage 3r344410. , and the implementation of the [b] method. canHandle 3r344410. will look the above way. 3r34415.  3r3447. 3r34415.  3r3447. But if the "reset" Drop Since images are going on OUTSIDE, then we need to handle only those “drag and drop” Drag which represent the image [b] UIImage 3r344410. along with 3r340405. URL 3r340346. for this image, since we are not going to store the images themselves themselves [b] UIImage 3r344410. in the model. In this case, I will return [b] true 3r344410. in method 3r340407. canHandle 3r344410. Only if the pair of conditions [b] is fulfilled simultaneously. session.canLoadObjects (ofClass: NSURL.self) && session.canLoadObjects (ofClass: UIImage.self) 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r31734. 3r34415.  3r3447. 3r34415.  3r3447. It remains for me to determine whether I am dealing with a "dumping" EXTERNAL or INSIDE. I will do this with the help of the calculated constant [b] isSelf 3r344410. , for which I can use such a thing for Drop Sessions 3r334407. session 3r344410. as its local Drag session 3r340407. localDragSession 3r344410. . This local Drag The session, in turn, is the local context 3r340407. localContext 3r344410. . 3r34415.  3r3447. If you remember, we set this local context in the [b] method. itemsForVeginning 3r344410. 3r340405. Drag delegate 3r340347. UICollectionViewDragDelegate 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. localContext 3r344410. on the equality of my collection [b] collectionView 3r344410. . True TYPE at [b] localContext 3r344410. will be [b] Any 3r344410. , and I need to make a "casting" TYPE [b] Any 3r344410. using the [b] operator. as? UICollectionView 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r31840. 3r34415.  3r3447. 3r34415.  3r3447. If the local context is [b] (session.localDragSession? .localContext as? UICollectionView) 3r344410. equal to my collection [b] collectionView 3r344410. , then the calculated variable is [b] isSelf 3r344410. equals [b] true 3r344410. and there is a local "reset" INSIDE my collection. If this equality is violated, then we are dealing with a “reset” Drop Izvne. 3r34415.  3r3447. 3r34415.  3r3447. Method [b] canHandle 3r344410. reports that we can handle only this kind of “drag and drop” 3r-34405. Drag on our collection Collection View . Otherwise, it doesn’t make sense at all to talk about a “reset” 3r34405. Drop . 3r34415.  3r3447. 3r34415.  3r3447. If we continue to "reset" Drop , then even before the moment when the user lifts his fingers from the screen and there is a real “reset” Drop , we have to report iOS 3r334406. using the [b] method. dropSessionDidUpdate 3r344410. delegate 3r340347. UICollectionViewDropDelegate 3r344410. about our offer [b] UIDropProposal 3r344410. to perform the reset Drop . 3r34415.  3r3447. 3r34415.  3r3447. In this method we have to return Drop a sentence that may have the values ​​ [b] .copy 3r344410. or [b] .move 3r344410. or [b] .cancel 3r344410. or [b] .forbidden 3r344410. for the argument [b] operation 3r3439393. 3r344410. . And these are all the possibilities that we have in the ordinary case when dealing with the usual [b] UIView 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. But a collection of Collection View goes further and offers to return the special offer [b] UICollectionViewDropProposal 3r344410. which is 3r340345. subclass class [b] UIDropProposal 3r344410. and allows for operation besides operation 3r340407. operation 3r3439393. 3r344410. also indicate the optional parameter [b] intent 3r344410. for the collection. Collection View . 3r34415.  3r3447. 3r34415.  3r3447. Parameter 3r340347. intent 3r344410. reports collection 3r340405. Collection View about whether we want the "reset" element to be placed inside an existing cell 3r340407. cell 3r344410. or we want to add a new cell [b] cell 3r344410. See the difference? In the case of the collection. Collection View we must report our intention to [b] intent 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. In our case, we always want to add a new cell, so you will see what our parameter is [b] intent 3r344410. . 3r34415.  3r3447. Select the second constructor for [b] UICollectionViewDropProposal 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r-31999. 3r34415.  3r3447. 3r34415.  3r3447. In our case, we always want to add a new cell and the parameter 3r340407. intent 3r344410. will take the value [b] .insertAtDestinationIndexPath 3r344410. as opposed to 3r340347. .insertIntoDestinationIndexPath 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. 3r32020. 3r34415.  3r3447. 3r34415.  3r3447. I again used the calculated constant [b] isSelf 3r344410. and if it is [b] self 3r344410. reorganization, then I perform the move [b] .move 3r344410. otherwise I am copying [b] .copy 3r344410. . In both cases, we use [b] .insertAtDestinationIndexPath 3r344410. , that is, the insertion of new cells [b] cells 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. So far I have not implemented the [b] method. performDrop 3r344410. , but let's take a look at what the collection can already do. Collection View with this little piece of information we gave her. 3r34415.  3r3447. 3r34415.  3r3447. I am dragging an image from 3r34405. Safari with a search engine Google 3r340346. , and this image has a green "+" sign on top, indicating that our Gallery of Images is not only ready to receive and copy this image along with its 3r340405. URL 3r340346. but also provide a place inside the collection Collection View : 3r344415.  3r3447. 3r34415.  3r3447. 3r32075. 3r34415.  3r3447. 3r34415.  3r3447. I can click on a couple more images in 3r334345. Safari , and the “dragged” images will become 3: 3r344415.  3r3447. 3r34415.  3r3447. 3r32086. 3r34415.  3r3447. 3r34415.  3r3447. But if I lift my finger and “drop” 3r34405. Drop these images, they will not be located in our Gallery, but will simply return to their former places, because we have not yet implemented the [b] method. performDrop 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. Collection View already knows what I want to do. 3r34415.  3r3447. Collection Collection View - an absolutely wonderful thing for the mechanism. Drag & Drop , it has very powerful functionality for this. We barely touched it, having written 4 lines of code, and it already advanced far enough in the perception of “reset” 3r340405. Drop . 3r34415.  3r3447. Let's go back to the code and implement the [b] method. performDrop 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. performDrop 3r344410. a little harder, but not too much. 3r34415.  3r3447. When a “reset” occurs, r3r34405. Drop , then in method [b] performDrop 3r344410. we need to update our Model, which is the [b] image gallery. imageGallery 3r344410. with a list of images [b] images 3r344410. , and we need to update our visual collection [b] collectionView 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. We have two different “reset” scenarios for 3r34405. Drop . 3r34415.  3r3447. 3r34415.  3r3447. There is a “reset” 3r334405. Drop carried out from my collection [b] collectionView 3r344410. , then I have to do a “reset” 3r34405. Drop element of the collection in the new place and remove it from the old place, because in this case I move (3r334407. .move 3r3434393.
) this element of the collection. This is a trivial task. 3r34415.  3r3447. 3r34415.  3r3447. There is a “reset” 3r334405. Drop carried out from another application, then we must use the property itemProvider 3r344410. “Dragging” element [b] item 3r344410. for sampling data. 3r34415.  3r3447. 3r34415.  3r3447. When we perform a “reset” Drop in collection 3r340407. collectionView 3r344410. , the collection provides us with a coordinator [b] coordinator 3r344410. . The first and most important thing that the coordinator tells us is [b] coordinator 3r344410. This is [b] destinationIndexPath 3r344410. that is, [b] indexPath 3r344410. “Destination” “reset” 3r34405. Drop , that is, where we will “dump”. 3r34415.  3r3447. 3r34415.  3r3447. destinationIndexPath 3r344410. may be equal to r3r34407. nil 3r3439393. 3r344410. as you can drag the “dumped” image into that part of the collection. Collection View which is not the place between any already existing cells 3r340407. cells 3r344410. , so that it may well be [b] nil 3r3439393. 3r344410. . If it is this situation that happens, then I create [b] IndexPath 3r344410. with the 0th element [b] item 3r344410. in the 0th section [b] section 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. indexPath 3r344410. , but this [b] indexPath 3r344410. I will use the default. 3r34415.  3r3447. 3r34415.  3r3447. Now we know where we will be doing the “reset” 3r34405. Drop . We have to go through all the “dumped” elements of 3r340407. coordinator.items 3r344410. provided by the coordinator [b] coordinator 3r344410. . Each element [b] item 3r344410. from this list has TYPE [b] UICollectionViewDropItem 3r344410. and can provide us with very interesting pieces of information. 3r34415.  3r3447. 3r34415.  3r3447. For example, if I can get [b] sourceIndexPath 3r344410. from 3r340347. item.sourceIndexPath 3r344410. then I will definitely know that this is “dragging” Drag runs from itself, [b] self 3r344410. , and the source of drag and drop Drag is an element of the collection with [b] indexPath 3r344410. equal [b] sourceIndexPath 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. localContext 3r344410. in this case, to find out that this “drag and drop” was done INSIDE the collection [b] collectionView 3r344410. . Great! 3r34415.  3r3447. 3r34415.  3r3447. Now I know the source [b] sourceIndexPath 3r344410. and “destination” 3r34407. destinationIndexPath 3r344410. 3r340405. Drag & Drop and the task becomes trivial. All I need to do is update the Model so that the source and “destination-point” are swapped, and then update the [b] collection. collectionView 3r344410. , in which you need to remove the collection item with [b] sourceIndexPath 3r344410. and add it to the collection with [b] destinationIndexPath 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. Our local case is the simplest one, because in this case the mechanism. Drag & Drop It works not just in the same application, but also in the same collection [b] collectionView 3r344410. and I can get all the necessary information with the help of the coordinator [b] coordinator 3r344410. . Let's implement it the simplest local case:
 3r3447. 3r34415.  3r3447. localObject 3r344410. which I “hid” earlier when I created 3r340407. dragItem 3r344410. and which I can now borrow from the “drag-and-drop” item of the 3r-34407 collection. item 3r344410. in the form of 3r340407. item.localObject 3r344410. . We need it when “resetting” 3r34034. Drop images in the "trash can", which is in the same application, but is not the same collection [b] collectionView 3r344410. . Now two r3r34407 is enough for me. IndexPathes 3r344410. : source 3r340347. sourceIndexPath 3r344410. and “destination” 3r34407. destinationIndexPath 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. First I get the information [b] imageInfo 3r344410. about the image in the old place from the Model, removing it from there. And then I insert into the array [b] images 3r344410. My Models [b] imageGallery 3r344410. information [b] imageInfo 3r344410. about the image with the new index [b] destinationIndexPath.item 3r344410. . That's how I updated my Model:
 3r3447. 3r34415.  3r3447. collection itself. collectionView 3r344410. . It is very important to understand that I do not want to overload all the data in my collection [b] collectionView 3r344410. using 3r340347. reloadData () 3r344410. in the middle of the “drag and drop” process Drag because it reinstalls the whole “World” of our Image Gallery, which is very bad, DO NOT DO IT. Instead, I'm going to remove and insert the elements 3r340347. items 3r344410. individually: 3r3444415.  3r3447. 3r34415.  3r3447. collection. collectionView 3r344410. from 3r340347. sourceIndexPath 3r344410. and inserted a new collection item with [b] destinationIndexPath 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. It looks like this code works great, but in reality, this code can “crash” your application. The reason is that you make numerous changes in your [b] collection. collectionView 3r344410. , and in this case, each step of the collection change must be normally synchronized with the Model, which in our case is not respected, since we perform both operations at the same time: deletion and insertion. Consequently, the [b] collection. collectionView 3r344410. will be at some point in a non-synchronized state with the Model. 3r34415.  3r3447. 3r34415.  3r3447. But there is a really cool way around this, which is that of the [b] collection. collectionView 3r344410. There is a method named [b] performBatchUpdates 3r344410. which has a closure ( closure ) and inside this closure I can place any number of these 3r340347. deleteItems 3r344410. , 3r340347. insertItems 3r344410. , 3r340347. moveItems 3r344410. and all I want:
 3r3447. 3r34415.  3r3447. deleteItems 3r344410. and 3r340347. insertItems 3r344410. will be performed as a single operation, and there will never be a lack of synchronization of your Model with the 3r340407 collection. collectionView 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. And finally, the last thing we need to do is ask the coordinator [b] coordinator 3r344410. implement and animate itself “reset” 3r34034. Drop : 3r344415.  3r3447. 3r34415.  3r3447. 3r34415.  3r3447. 3r34415.  3r3447. and reset it: 3r34415.  3r3447. 3r34415.  3r3447. else 3r344410. in relation to 3r340407. sourceIndexPath 3r344410. . If we do not have [b] sourceIndexPath 3r344410. then this means that the “reset” item came from somewhere outside and we will have to use data transfer using 3r34407. itemProver 3r344410. of the reset item [b] item.dragItem.itemProvider
 3r3447. 3r34415.  3r3447. Drag From outside and “throw” 3r34405. Drop Does this information become available instantly? No, you select data from the “drag and drop” thing ASYNCHRONOUS. But what if the sample takes 10 seconds? What will the collection do at this time? Sollection View ? In addition, the data may not come at all in the order in which we requested it. Managing this is not easy at all, and Apple offered for 3r340405. Sollection View in this case, a completely new technology of using substitutes of 3r34405. Placeholders . 3r34415.  3r3447. 3r34415.  3r3447. You place in your collection Collection View placeholder Placeholder , And a collection of Collection View manages it all for you, so all you have to do when the data is finally selected is to ask for the 3r-34405 locator. Placeholder call its context placeholderContext 3r344410. and inform him that you received the information. Then aboutupdate your Model and context [b] placeholderContext 3r344410. AUTOMATICALLY swaps the cell 3r340407. cell 3r344410. with a substitute Placeholder on one of your cells [b] cells 3r344410. that matches the type of data you received. 3r34415.  3r3447. 3r34415.  3r3447. We perform all these actions by creating the context of the substitute [b] placeholderContext 3r344410. which manages the substitute Placeholder and which you get from the coordinator [b] coordinator 3r344410. by asking “reset” 3r34034. Drop element [b] item 3r344410. on the substitute Placeholder . 3r34415.  3r3447. 3r34415.  3r3447. I will use the initializer for the context substitute for [b] placeholderContext 3r344410. that “throws” [b] dragItem 3r344410. on 3r340407. UICollectionViewDropPlaceholder 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. Drop This is [b] item.dragItem 3r344410. where [b] item 3r344410. - This is an element [b] for 3r344410. cycle, so how can we “throw” Drop many objects 3r340407. coordinator.items 3r344410. . We “throw” them one by one. So, [b] item.dragItem 3r344410. - this is what we “drag” Drag and “throw” Drop . The next argument to this function is the placer, and I will create it using the initializer [b] UICollectionViewDropPlaceholder 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. Placeholder that is, [b] insertionIndexPath 3r344410. and the ID of the reusable cell 3r340347. reuseIdentifier 3r344410. . 3r34415.  3r3447. Argument [b] insertionIndexPath 3r344410. obviously equal to r3r34407. destinationIndexPath 3r344410. This is [b] IndexPath 3r344410. to accommodate a drag-and-drop object, it is calculated at the very beginning of the [b] method. performDropWith 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. Now look at the identifier for the reusable cell [b] reuseIdentifier 3r344410. . You must decide what type of cell [b] cell 3r344410. is your placer Placeholder . The coordinator [b] coordinator 3r344410. there is no “pre-assembled” cell 3r334407. cell 3r344410. for the placer Placeholder . It is YOU who should decide on this cell [b] cell 3r344410. . Therefore, the identifier for the reused cell is [b] reuseIdentifiercell 3r344410. from your storyboard so that it can be used as a PROTOTYPE. 3r34415.  3r3447. 3r34415.  3r3447. I will call it “DropPlaceholderCell”, but in principle, I could call it whatever you like. 3r34415.  3r3447. This is just the line [b] String 3r3434393. 3r344410. which I am going to use on my storyboard to create this thing. 3r34415.  3r3447. We return to our storyboard and create the [b] cell. cell 3r344410. for the placer Placeholder . To do this, we just need to select the collection. Collection View and inspect it. In the very first field Items I'm changing 1 on 3r340405. 2 . This immediately creates a second cell for us, which is an exact copy of the first. 3r34415.  3r3447. 3r34415.  3r3447. ImageCell , set the identifier “ DropPlaceholderCell ”, Remove from there all UI elements including 3r340405. Image View , because this PROTOTYPE is used when the image has not yet arrived. Add a new activity indicator 3r340345 from the Objects Palette. Activity Indicator , it will rotate, letting users know that I expect some “discarded” data. Also change the background color Background , in order to understand that when “resetting” images from OUTSIDE, this particular cell 3r-34407 works. cell 3r344410. as a PROTOTYPE:
 3r3447. 3r34415.  3r3447. ImageCollectionVewCell
3r344410. because there will be no images in it. I will make this cell a regular cell TYPE [b] UICollectionCiewCell 3r344410. since we don't need any Outlets 3r340346. for management: 3r344415.  3r3447. 3r34415.  3r3447. so that it starts animating from the very beginning, and I wouldn’t have to write anything in code to run it. To do this, click on the option 3r340345. Animating : 3r344415.  3r3447. 3r34415.  3r3447. DropPlaceholderCell , back to our code. Now we have a great replacement for Placeholder ready to go. 3r34415.  3r3447. 3r34415.  3r3447. All that is left for us to do is receive the data, and when the data is received, we just say about this context 3r340407. placeholderСontext 3r344410. and he swaps the substitute Placeholder and our “native” data cell, and we will make changes in the Model. 3r34415.  3r3447. 3r34415.  3r3447. I'm going to “download” the ONE object that my 3r340407 will be. item 3r344410. using the [b] method. loadObject (ofClass: UIImage.self) 3r344410. (singular). I am using the code [b] item.dragItem.itemProvider 3r344410. With supplier 3r340347. itemProvider 3r344410. which will provide me with the data element [b] item 3r344410. ASYNCHRONO. It is clear that if connected [b] iitemProvider 3r344410. , then the object is “reset” [b] iitem 3r344410. we get outside of this application. This is followed by the method [b] loadObject (ofСlass: UIImage.self) 3r344410. (in the singular): 3r34415.  3r3447. 3r34415.  3r3447. main queue . And, unfortunately, we had to switch to main queue using 3r340347. DispatchQueue.main.async {} 3r344410. in order to “catch” the aspect ratio of the image into a local variable [b] aspectRatio 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. We actually entered two local variables [b] imageURL 3r344410. and 3r340347. aspectRatio 3r344410. 3r34415.  3r3447. 3r34415.  3r3447. image 3r344410. and URL 3r34407. url 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r33024. 3r34415.  3r3447. 3r34415.  3r3447. If both are local variables [b] imageURL 3r344410. and 3r340347. aspectRatio 3r344410. not equal to r3r34407. nil 3r3439393. 3r344410. we will ask for the context of the placer [b] placeholderСontext 3r344410. using the [b] method. commitInsertion 3r344410. give us the opportunity to change our Model [b] imageGallery 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r33057. 3r34415.  3r3447. 3r34415.  3r3447. In this expression, we have [b] insertionIndexPath 3r344410. - this is [b] indexPath 3r344410. to insert, and we change our Model [b] imageGallery 3r344410. . This is all we need to do, and this method AUTOMATICALLY replaces the substitute Placeholder on cell 3r340407. cell 3r344410. by calling the normal method [b] cellForItemAt 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. Notice that [b] insertionIndexPath 3r344410. may vary greatly from [b] destinationIndexPath 3r344410. . Why? Because data sampling may take 10 seconds, of course, unlikely, but it may take 10 seconds. During this time in the collection Collection View a lot can happen. New cells may be added [b] cells 3r344410. , everything happens fast enough. 3r34415.  3r3447. 3r34415.  3r3447. ALWAYS use [b] here. insertionIndexPath 3r344410. , and ONLY [b] insertionIndexPath 3r344410. , to upgrade your Model. 3r34415.  3r3447. 3r34415.  3r3447. How do we update our model? 3r34415.  3r3447. 3r34415.  3r3447. We insert [b] into the array. imageGallery.images 3r344410. structure [b] imageModel 3r344410. composed of the aspect ratio of the image 3r340347. aspectRatio 3r344410. and the image URL is 3r340407. imageURL 3r344410. which returned us the corresponding [b] provider 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. This updates our Model [b] imageGallery 3r344410. , and the method [b] commitInsertion 3r344410. does everything else for us. No more do you need to do anything extra, no inserts, delete rows, none of this. And, of course, since we are in closure, we need to add 3r340407. self. 3r3439393 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. 3r333332. 3r34415.  3r3447. 3r34415.  3r3447. If for some reason we could not get the aspect ratio of an image 3r340407. aspectRatio 3r344410. and 3r340405. URL 3r340346. images [b] imageURL 3r344410. from the corresponding 3r340407. provider 3r344410. may have received an error [b] error 3r344410. instead of [b] provider 3r344410. then we should let the context know [b] placeholderContext 3r344410. you need to destroy this placer Placeholder because we still can not get other dаta:
 3r3447. 3r34415.  3r3447. 3r333199. 3r34415.  3r3447. 3r34415.  3r3447. It is necessary to keep in mind one feature URLs 3r340346. that come from places like Google 3r340346. In reality they need minor transformations for genderteachings of the “pure” 3r340405. URL 3r340346. for the image. How this problem is solved can be seen in this demo application in the file 3r340405. Utilities.swift on 3r340408. Github . 3r34415.  3r3447. Therefore, when receiving 3r340405. URL 3r340346. the images we use property [b] imageURL 3r344410. from class 3r340407. URL 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r332330. 3r34415.  3r3447. 3r34415.  3r3447. And this is all you need to do to take something from inside inside the 3r34034 collection. Collection View . 3r34415.  3r3447. 3r34415.  3r3447. Let's see it in action. We start simultaneously in multitasking mode our demo application ImageGallery and 3r340405. Safari with a search engine Google 3r340346. . In 3r34034. Google 3r340346. We are looking for images on the theme "Dawn" (sunrise). In 3r34034. Safari already embedded Drag & Drop mechanism, so we can select one of these images, hold it for a long time, move it slightly and drag it to our Gallery of Images. 3r34415.  3r3447. 3r34415.  3r3447. is working at that time. Placeholder : 3r344415.  3r3447. 3r34415.  3r3447. 3r34415.  3r3447. 3r34415.  3r3447. After the download is complete, the “discarded” image is placed in the right place, and Placeholder disappears: 3r344415.  3r3447. 3r34415.  3r3447. 3r3323279. 3r34415.  3r3447. 3r34415.  3r3447. We can continue to “dump” images and place even more images in our collection:
 3r3447. 3r34415.  3r3447. works. Placeholder
: 3r344415.  3r3447. 3r34415.  3r3447. 3r33299. 3r34415.  3r3447. 3r34415.  3r3447. As a result, our Image Gallery is filled with new images: 3r34444.  3r3447. 3r34415.  3r3447. 3r333338. 3r34415.  3r3447. 3r34415.  3r3447. Now that it is clear that we are capable of receiving images OUTSIDE, we no longer need the test images and we remove them:
 3r3447. 3r34415.  3r3447. 3r333337. 3r34415.  3r3447. 3r34415.  3r3447. Our [b] viewDidLoad 3r344410. it becomes very simple: in it we make our Controller 3r340405. Drag and 3r340405. Drop delegate and add a gesture recognizer [b] 3r333333. pinch
3r344410. that governs the number of images per line:
 3r3447. 3r34415.  3r3447. 3r3333340. 3r34415.  3r3447. 3r34415.  3r3447. Of course, we can add a cache for images [b] imageCache 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r333333. 3r34415.  3r3447. 3r34415.  3r3447. We will fill [b] imageCache 3r344410. when "reset" Drop in method 3r340407. performDrop 3r344410. 3r34415.  3r3447. 3r34415.  3r3447. 3r3333372. 3r34415.  3r3447. 3r34415.  3r3447. and when sampling from the "network" in the user class 3r340407. ImageCollectionViewCell 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r333335. 3r34415.  3r3447. 3r34415.  3r3447. And use the cache [b] imageCache 3r344410. will be when playing cell [b] cell 3r344410. of our User Class Image Gallery [b] ImageCollectionViewCell 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r333336. 3r34415.  3r3447. 3r34415.  3r3447. Now we start with an empty collection
 3r3447. 3r34415.  3r3447. 3r333335. 3r34415.  3r3447. 3r34415.  3r3447. then "throw" a new image on our collection
 3r3447. 3r34415.  3r3447. 3r333424. 3r34415.  3r3447. 3r34415.  3r3447. there is a download image and Placeholder working 3r34415.  3r3447. 3r34415.  3r3447. 3r333335. 3r34415.  3r3447. 3r34415.  3r3447. and the image appears in the right place: 3r344415.  3r3447. 3r34415.  3r3447.  3r3447. 3r34415.  3r3447. Placeholders working 3r34415.  3r3447. 3r34415.  3r3447. 3r333464. 3r34415.  3r3447. 3r34415.  3r3447. And the images appear in the right place: 3r34415.  3r3447. 3r34415.  3r3447. 3r333333. 3r34415.  3r3447. 3r34415.  3r3447. So, we can do a lot with our Image Gallery: fill it with EXTERNAL, reorganize elements INSIDE, share images with other applications. 3r34415.  3r3447. It remains for us to teach her to get rid of unnecessary images by “resetting” them to 3r-34405. Drop in the “trash can” displayed on the navigation bar on the right. As described in the section “Features of the“ Image Gallery ”demo application,” “trash can” is represented by a class of 3-334347. GabageView 3r344410. which inherits from [b] UIView 3r344410. and we have to teach him to take images from our 3r334405 collection. Sollection View . 3r34415.  3r3447. 3r34415.  3r3447. 3r3436969. Reset 3r340405. Drop Images Gallery in the "trash can". 3r34370. 3r34415.  3r3447. Right off the bat - into the quarry. I will add to [b] GabageView 3r344410. “Interaction” [b] interaction 3r344410. and it will be [b] UIDropInteraction 3r344410. since i'm trying to get a "reset" Drop some sort of thing. All we have to do is provide this [b] UIDropInteraction 3r344410. This is delegate [b] delegate 3r344410. and I'm going to nominate myself, [b] self 3r344410. by this delegate 3r340347. delegate 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r333356. 3r34415.  3r3447. 3r34415.  3r3447. Naturally, our class is [b] GabageView 3r344410. must confirm that we are implementing the [b] protocol. UIDropInteractionDelegate 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. , it is to implement methods already known to us [b] canHandle 3r344410. , 3r340347. sessionDidUpdate 3r344410. and 3r340347. performDrop 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. 3r333576. 3r34415.  3r3447. 3r34415.  3r3447. However, unlike similar methods for the collection. Collection View , we have no additional information in the form of [b] indexPath 3r344410. dumping points. 3r34415.  3r3447. 3r34415.  3r3447. Let's implement these methods. 3r34415.  3r3447. Inside the [b] method. canHandle 3r344410. only those “drag and drop” operations will be processed. Drag which are [b] images. UIImage 3r344410. . Therefore, I will return [b] true 3r344410. only if [b] session.canLoadObjects (ofClass: UIImage.self) 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r3333615. 3r34415.  3r3447. 3r34415.  3r3447. In method 3r340347. canHandle 3r344410. in essence, you simply report that if the “dragging” object is not an image 3r340407. UIImage 3r344410. then it does not make sense to continue dropping the Drop and invoking subsequent methods. 3r34415.  3r3447. If the “dragging” object is an image 3r340407. UIImage 3r344410. then we will execute the method [b] sessionDidUpdate 3r344410. . All we need to do in this method is to return our proposal [b] UIDropProposal 3r344410. on the “reset” Drop . And I am ready to accept only a “dragging” LOCALLY object of the TYPE of the image [b] UIImage 3r344410. which can be “reset” Drop anywhere inside my [b] GarbageView 3r3439393. 3r344410. . My GarbageView 3r3439393. will not interact with images reset by OUTSIDE. Therefore, I am analyzing with the help of the variable [b] session.localDragSession 3r344410. , is there a local “reset” 3r34405. Drop , and return the “reset” clause in the form of a [b] constructor. UIDropProposal 3r344410. with the argument [b] operation 3r3439393. 3r344410. taking the value 3r340347. .copy 3r344410. because ALWAYS LOCAL “dragging” Drag in my application will come from the collection. Collection View . If there is a "dragging" Drag and “reset” 3r334405. Drop IZVNE, then I return the sentence "reset" in the form of the designer [b] UIDropProposal 3r344410. with the argument [b] operation 3r3439393. 3r344410. taking the value 3r340347. .fobbiden 3r344410. , that is, "prohibited" and instead of the green plus sign "+" we will receive the sign of the prohibition of "reset". 3r34415.  3r3447. 3r34415.  3r3447. UIImage 3r344410. , we will simulate reducing its scale to almost ? and when the “reset” happens, we will remove this image from the 3r34034 collection. Collection View . 3r34415.  3r3447. In order to create the illusion of the user “reset and disappear” images in the “garbage can”, we use the new for us method 3r340347. previewForDropping 3r344410. which allows you to redirect the "reset" 3r34034. Drop to another place and at the same time transform the “dumped” object in the process of animation:
 3r3447. 3r34415.  3r3447. 3r333331. 3r34415.  3r3447. 3r34415.  3r3447. In this method using the initializer [b] UIDragPreviewTarget 3r344410. we get a new [b] preView 3r3439393. 3r344410. for the dropping object [b] target 3r344410. and redirect it using the [b] method. retargetedPreview 3r344410. to a new place, to the “trash can”, with its scale decreasing to almost zero:
 3r3447. 3r34415.  3r3447. 3r333336. 3r34415.  3r3447. 3r34415.  3r3447. If the user lifted a finger up, then there is a "reset" 3r340405. Drop , and I (as [b] GarbageView
) receive the message 3r334407. performDrop 3r344410. . The message is 3r340407. performDrop 3r344410. we do the actual “reset” 3r34034. Drop . Honestly, self dropped on [b] GarbageView 3r3439393. 3r344410. we are no longer interested in the image, since we will make it almost invisible, most likely the very fact of the completion of the “reset” 3r34040. Drop will signal that we remove this image from the collection. Collection View 3r340346. . In order to accomplish this, we need to know the [b] collection itself. collection 3r344410. and 3r340347. indexPath 3r344410. dumped image in it. Where can we get them from? 3r34415.  3r3447. 3r34415.  3r3447. Since the process is 3r340405. Drag & Drop happens in one application, then everything local is available to us: local Drag session 3r340407. localDragSession 3r344410. our Drop Sessions 3r334407. session 3r344410. , local context [b] localContext 3r344410. which is our collection [b] сollectionView 3r344410. and the local object 3r340347. localObject 3r344410. which we can do self discharged image [b] image 3r344410. from the “Gallery” or its [b] indexPath 3r344410. . Because of this, we can get in method [b] performDrop 3r344410. class [b] GarbageView 3r3439393. 3r344410. [b] collection. collection 3r344410. , and using it [b] dataSource 3r344410. as [b] ImageGalleryCollectionViewController 3r344410. and Model 3r340407. imageGallery 3r344410. our Controller , we can get an array of images [b] images 3r344410. TYPE[ImageModel]: 3r344415.  3r3447. 3r34415.  3r3447. 3r333855. 3r34415.  3r3447. 3r34415.  3r3447. Using the local Drag Sessions 3r334407. localDragSession 3r344410. our Drop Sessions 3r334407. session 3r344410. we managed to get all the “tugs” on 3r340407. GarbageView 3r3439393. 3r344410. 3r340405. Drag Elements 3r340347. items 3r344410. , and there may be a lot of them, as we know, and all of them are images of our collection [b] collectionView 3r344410. . Creating Drag Elements 3r340347. dragItems 3r344410. Our collection Collection View , we have provided for each "overtightened" 3r340405. Drag element [b] dragItem 3r344410. local object [b] localObject 3r344410. which is the image [b] image 3r344410. However, it was not useful to us in the internal reorganization of the 3r340407 collection. collectionView 3r344410. , but when “dumping” Gallery images into a “trash can” we urgently need a local object 3r340407. localObject 3r344410. “Overtightened” object [b] dragItem 3r344410. , because this time we have no coordinator [b] coordinator 3r344410. which so generously shares information about what is happening in the [b] collection. collectionView 3r344410. . Therefore, we want the local object 3r340347. localObject 3r344410. There was an index 3r340407. indexPath 3r344410. in the image array [b] images 3r344410. Our Model [b] imageGallery 3r344410. . Make the necessary changes to the [b] method. dragItems (at indexPath: IndexPath) 3r344410. class [b] ImageGalleryCollectionViewController 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r? 33956. 3r34415.  3r3447. 3r34415.  3r3447. Now we will be able to take from each element of “rush through” [b] item 3r344410. its [b] localObject 3r344410. which is the index 3r340347. indexPath 3r344410. in the image array [b] images 3r344410. Our Model [b] imageGallery 3r344410. and send it to the array array [b] indexes 3r344410. and into the [b] array. indexPahes 3r344410. deleted images:
 3r3447. 3r34415.  3r3447. 3r? 33993. 3r34415.  3r3447. 3r34415.  3r3447. Knowing an array of indices [b] indexes 3r344410. and the [b] array. indexPahes 3r344410. deleted images, in method [b] performBatchUpdates 3r344410. [b] collections. collection 3r344410. we remove all deleted images from the [b] model. images 3r344410. and from the [b] collection. collection 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r34026. 3r34415.  3r3447. 3r34415.  3r3447. Launch the application, fill the Gallery with new images:
 3r3447. 3r34415.  3r3447. 3r34035. 3r34415.  3r3447. 3r34415.  3r3447. Select a couple of images that we want to remove from our Gallery
 3r3447. 3r34415.  3r3447. 3r34044. 3r34415.  3r3447. 3r34415.  3r3447. we “throw” them onto the “trash can” icon 3r3444415.  3r3447. 3r34415.  3r3447. 3r34053. 3r34415.  3r3447. 3r34415.  3r3447. They decrease to almost 0
 3r3447. 3r34415.  3r3447. 3r34062. 3r34415.  3r3447. 3r34415.  3r3447. and disappear from the collection. Collection View hiding in the "trash can":
 3r3447. 3r34415.  3r3447. 3r34073. 3r34415.  3r3447. 3r34415.  3r3447. 3r3436969. Saving images between runs. 3r34370. 3r34415.  3r3447. 3r34415.  3r3447. To save the Gallery of images between launches, we will use 3r340407. UserDefaults 3r344410. , after converting our Model to JSON 3r340346. format. For this we will add to our Controller variable [b] var defailts 3r344410. 3r34415.  3r3447. 3r34415.  3r3447. 3r? 34100. 3r34415.  3r3447. 3r34415.  3r3447. , and in the structure of the Model [b] ImageGallery 3r344410. and 3r340347. ImageModel 3r344410. protocol 3r340347. Codable 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r34121. 3r34415.  3r3447. 3r34415.  3r3447. Lines [b] String 3r3434393. 3r344410. , arrays [b] Array 3r344410. , 3r340347. URL 3r344410. and 3r340347. Double 3r344410. already implement the [b] protocol. Codable 3r344410. so we don’t have to do anything else to make the encoding and decoding work for Model [b] ImageGallery 3r344410. in 3r340405. JSON 3r340346. format. 3r34415.  3r3447. How do we get 3r340345. JSON 3r340346. version [b] ImageGallery 3r344410. ? 3r34415.  3r3447. To do this, create a calculated variable [b] var json 3r344410. which returns the result of an attempt to transform itself, 3r340347. self 3r344410. using 3r340347. JSONEncoder.encode () 3r344410. in 3r340405. JSON 3r340346. Format: 3r34415.  3r3447. 3r34415.  3r3447. will be returned. Data 3r34393. 3r344410. as a result of the [b] conversion. self 3r344410. in the format 3r340405. JSON 3r340346. or 3r340347. nil 3r3439393. 3r344410. , if it is not possible to perform this conversion, although the latter never occurs, because this TYPE is 100% [b] Encodable 3r344410. . Used [b] Optional 3r344410. variable [b] json 3r344410. just for symmetry reasons. 3r34415.  3r3447. Now we have a way to transform the Model [b] ImageGallery 3r344410. in 3r340407. Data 3r34393. 3r344410. 3r340345 format. JSON 3r340346. . In this case, the variable [b] json 3r344410. has a TYPE [b] Data? 3r3439393 3r344410. which can be memorized in [b] UserDefaults 3r344410. . 3r34415.  3r3447. Now imagine that somehow we managed to get JSON 3r340346. data 3r340347. json 3r344410. , and I would like to recreate from them our Model, a copy of the [b] structure. ImageGallery 3r344410. . For this, it is very easy to write an INITIALIZER for 3r340347. ImageGallery 3r344410. whose input argument is JSON 3r340346. data 3r340347. json 3r344410. . This initializer will be a “falling” initializer (3r34405. Failable 3r340406.). If it fails to initialize, then it “falls” and returns 3r34034. nil 3r3439393. 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r334267. 3r34415.  3r3447. 3r34415.  3r3447. I just get the new value [b] newValue 3r344410. using decoder [b] JSONDecoder 3r344410. trying to decode the data [b] json 3r344410. which are passed to my initializer, and then assign it to [b] self 3r344410. . 3r34415.  3r3447. If I manage to do this, then I get a new instance of 3r340407. ImageGallery 3r344410. , but if my attempt fails, then I return 3r334347. nil 3r3439393. 3r344410. because my initialization failed. 3r34415.  3r3447. I must say that here we have a lot more reasons to “fail” (3r34034. Fail 3r340406.), Because it is possible that 3r34405. JSON 3r340346. data 3r340347. json 3r344410. may be corrupted or empty, all of which can lead to a “fall” (3r-34405. fail 3r-34406.) of the initializer. 3r34415.  3r3447. 3r34415.  3r3447. Now we can implement READING JSON 3r340346. Data and Restore Models [b] imageGallery 3r344410. in method 3r340407. viewWillAppear 3r344410. our Controller
3r34415.  3r3447. 3r34415.  3r3447. 3r34330. 3r34415.  3r3447. 3r34415.  3r3447. as well as a RECORD in the observer 3-334407. didSet {r3r34393}. 3r344410. properties [b] imageGallery 3r344410. : 3r344415.  3r3447. 3r34415.  3r3447. 3r3r4347. 3r34415.  3r3447. 3r34415.  3r3447. Let's launch the application and fill our Gallery with images:
 3r3447. 3r34415.  3r3447. 3r335346. 3r34415.  3r3447. 3r34415.  3r3447. If we close the application and open it again, we will see our previous Gallery of images, which was saved in 3r34407. UserDefaults 3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. 3r3436969. Conclusion 3r34370. 3r34415.  3r3447. In this article, using the example of a very simple demo application “Image Gallery”, demonstrated how easy it is to implement the technology 3r340405. Drag & Drop
in 3r340405. iOS 3r334406. attachment. This allowed us to fully edit the Gallery of Images, “throwing” new images there from other applications, moving existing ones and removing unnecessary ones. And also to distribute images accumulated in the Gallery to other applications. 3r34415.  3r3447. 3r34415.  3r3447. Of course, we would like to create many such thematic pictorial collections of images and save them directly on the iPad or on iCloud Drive. This can be done if each such Gallery is interpreted as a permanently stored document [b] UIDocument 3r344410. . This interpretation will allow us to rise to the next level of abstraction and create an application that works with documents. In this application, your documents will show the component [b] DocumentBrowserViewController 3r344410. , very similar to the app Files . It allows you to create documents [b] UIDocument 3r344410. Type “image gallery” like on your iPad , and on iCloud Drive and also select the desired document for viewing and editing. 3r34415.  3r3447. But this is the subject of the next article. 3r34415.  3r3447. 3r34415.  3r3447. P.S. The code of the demonstration application prior to the implementation of the mechanism 3r34405. Drag & Drop
and after is located on [b] 3r34034. Github
3r344410. . 3r34415.  3r3447. 3r34415.  3r3447. 3r34415.  3r3447. 3r34423. 3r3447. 3r3447. 3r344420. ! function (e) {function t (t, n) {if (! (n in e)) {for (var r, a = e.document, i = a.scripts, o = i.length; o-- ;) if (-1! == i[o].src.indexOf (t)) {r = i[o]; break} if (! r) {r = a.createElement ("script"), r.type = "text /jаvascript", r.async =! ? r.defer =! ? r.src = t, r.charset = "UTF-8"; var d = function () {var e = a.getElementsByTagName ("script")[0]; e.parentNode.insertBefore (r, e)}; "[object Opera]" == e.opera? a.addEventListener? a.addEventListener ("DOMContentLoaded", d ): d ()}}} t ("//mediator.mail.ru/script/2820404/"""_mediator") () (); 3r34421. 3r3447. 3r34423. 3r3447. 3r3447. 3r3447. 3r3447.
+ 0 -

Add comment