I believe that the students do app development, for some third-party statistical analysis, error collection, such as the SDK should be not unfamiliar. At present, there are many products of the same function in the market, dazzling, people can not choose which SDK is the most reliable. Then choose a trial first!
So the question is: if the project is almost done and found that the SDK is really pit dad, not only poor scalability, but also often let app Crash, then you will think of replacing this SDK?
OK, then we'll try another one. Download SDK down, a look, dumbfounded, design style, package module is completely different, so we went to the project to find the global search before the SDK code to kill, and then again to various places with the new SDK to write new logic to replace, the key is, In the middle do not know how many bugs will be generated, missing the number of unmodified code, in short, there will always be a feeling of unreliable.
Another is good, if the team grew up, these data analysis and so on suddenly want to do their own, after all, these valuable data and do not want to be so ceded to a third party company ~ this time you are not just want to say: "Hehe"
So this time the adapter mode is playing a role ~
What is adapter mode
Gof explains the adapter mode as follows:
Converts the interface of a class into another interface that the customer expects. The adapter mode makes it possible for those classes to work together because the interface is incompatible and cannot work together.
Personal Popular Understanding:
Adapters: As the name implies, incompatible conversions are compatible, such as power adapters, which convert different voltages worldwide to the same voltage output to the target device.
The target device can be interpreted as an "interface", and the world's various voltages can be understood as "classes that produce the same functionality", and the power adapter can be understood as "the adapter class that needs to be implemented."
The effect of adapter mode is to quickly switch the source (data source, content source, etc.) without modifying the code or modifying very little code.
Like a power adapter, go to different countries, the same device requires only a different power adapter to use the current state of power, without the need to remove the machine.
Use the real scene
as is said at the beginning of the article, after the SDK pit of an alliance (indeed in some cases let app Crash, the reason for the initial judgment is to abuse performselector, do not consider the circumstances of the release of the object produced by the Crash), resulting in the substitution thought, Would it be hard to force ourselves to replace the future?
So in order to be easy in the future must move the brain to design code, so there is today's adapter mode combat.
How to use adapter mode
One adapter allows classes that are incompatible with the interface to work together. It wraps itself into an object, exposing a standard interface that interacts with this object.
If you are familiar with the adapter mode, you will notice that Apple has a different habit of implementing it-Apple use Protocol (protocols). You may be familiar with such agreements as Uitableviewdelegate, Uiscrollviewdelegate, nscoding and nscopying. Example, nscopying Protocol (protocol), any class can provide such a standard replication method.
The scrolling area we mentioned is like this:
Now, in the project Navigation View folder, right-click the mouse, select New File ..., and create a new class with the Ios\cocoa touch\object-c class template. The new class is named Horizontalscroller, and its subclass is UIView.
Open the HorizontalScroller.h file and insert the following code after the @end:
Copy Code code as follows:
@protocol horizontalscrollerdelegate <NSObject>
Methods declaration goes in
@end
This defines a horizontalscrollerdelegate name protocol, which inherits from the NSObject protocol, the same as a objective-c class that inherits its parent class. It is a good practice to comply with the NSObject agreement-or comply with the NSObject agreement. This allows you to send messages from the defined nsobject to the Horizontalscroller agent. You will see why this is important.
Defines the method that an agent executes, between @protocol and @end, which is divided into necessary and optional methods. Add the following protocol method:
Copy Code code as follows:
@required
Ask delegate how many views to display in the scrolling area
-(Nsinteger) Numberofviewsforhorizontalscroller: (horizontalscroller*) scroller;
Returns a view of index
-(uiview*) Horizontalscroller: (horizontalscroller*) scroller viewatindex: (int) index;
When the index is indexed the view is clicked, notify delegate
-(void) Horizontalscroller: (horizontalscroller*) scroller clickedviewatindex: (int) index;
@optional
Notifies the delegate that the index is the view when initialized. This method is optional.
Ask the delegate for the "index of the" initial view to display. This is optional
If not executed by delegate, the default value is 0
-(Nsinteger) Initialviewindexforhorizontalscroller: (horizontalscroller*) scroller;
Here we have the choice and the optional method we have defined. The required method must be executed by the broker, which typically contains data that a class must perform. The required method here is to get the number of views, the index of the view currently displayed, and the action to perform when the view is clicked. Optional method This is the initialization view, and the first indexed view will be displayed if Horizontalscroller is not executed.
Next, you need to define your new agent within the Horizontalscroller. But the definition of a protocol is below the definition of a class, so it is not visible at this point. What are you going to do?
The workaround is to declare the protocol earlier so that the compiler (and Xcode) knows that the protocol is available. OK, add the following code to the @interface:
[/ode]
@protocol horizontalscrollerdelegate;
[/code]
Or HorizontalScroller.h, add the following code between @interface and @end:
Copy Code code as follows:
@property (weak) id-(void) reload;
This attribute is defined as a weak. This is to prevent circulation retain. If a class holds a strong pointer (strong pointer) to its delegate (delegate), and the delegate keeps a strong pointer to the class, it can cause an app memory leak when the memory occupied by the class is freed.
ID means to assign this agent to a class that complies with Horizontalscrollerdelegate and gives you some type safety.
The reload method is to mimic the relaoddata of the UITableView class; it reloads all the data to create a horizontal moving view.
Replace the contents of HORIZONTALSCROLLER.M with the following code:
Copy Code code as follows:
#import "HORIZONTALSCROLLER.M"
#define View_padding 10
#define VIEW_DIMENSIONS 100
#define VIEW_OFFSET 100
@interface Horizontalscroller () <UIScrollViewDelegate>
@end
Copy Code code as follows:
@implementation Horizontalscroller
{
Uiscrollview *scroller;
}
@end
To explain each piece of code:
Constant definition, which makes it easy to modify the layout at design time. Within the scrolling view, the size of each picture is within a rectangle with a 100x100 inner margin of 10 dots (point).
Horizontalscroller comply with the Uiscrollviewdelegate agreement. Because Horizontalscroller uses a uiscrollview to scroll the album cover, it needs to know when the user stops scrolling.
Create a scrolling view that contains a picture.
Next you need to perform initialization. Add the following method:
Copy Code code as follows:
-(ID) initWithFrame: (CGRect) frame
{
self = [super Initwithframe:frame];
if (self) {
Scroller = [[Uiscrollerview alloc] Initwithframe:cgrectmake (0, 0, Frame.size.width, frame.size.height)];
Scroller.delegate = self;
UITapGestureRecognizer *taprecognizer = [[UITapGestureRecognizer alloc] initwithtarger:self action: @select ( scrollertapped:)];
[Scroller Addgesturerecognizer:taprecognizer];
}
return self;
}
Horizontalscroller will be scrolled through the entire fill of the view. If an album cover is clicked, UITapGestureRecognizer will listen for events on it. If it does, it notifies the Horizontalscroller agent.
Now add the following method:
Copy Code code as follows:
-(void) scrollertapped: (uitapgesturerecognizer*) gesture
{
Cgpoint location = [gesture LocationInView:gesture.view];
We can ' t use a enumerator here, because we don ' t want to enumerate over all of the Uiscrollview subviews.
We want to enumerate only the subview we added
for (int index=0; index<[self.delegate numberofviewforhorizontalscroller:self]; index++) {
UIView *view = Scroller.subviews[index];
if (Cgrectcontainspoint (view.frame, location)) {
[Self.delegate horizontalscroller:self Clickedviewatindex:index];
[Scroller Setcontentoffset:cgpointmake (VIEW.FRAME.ORIGIN.X-SELF.FRAME.SIZE.WIDTH/2 + VIEW.FRAME.SIZE.WIDTH/2, 0) Animated:yes];
Break
}
}
}
Gesture manipulation is like an incoming parameter that can be obtained from the Locationinview: get the location information.
Next, invoke the delegate's Numberofviewforhorizontalscroller: method. It must follow the Horizontalscrollerdelegate protocol to send the message securely, otherwise the Horizontalscroller instance's agent is unable to use the information.
Scroll through each view in the view and perform a hit test with Cgrectcontainspoint to find the clicked view. When the view is found, send a message to the delegate Horizontalscroller:clickedviewatindex:. When you jump out of this loop, set the clicked view to scroll into the middle of the view.
Now add the following code to refresh the scrolling view (scroller):
Copy Code code as follows:
-(void) Reload
{
1-nothing to load if there ' s no delegate
if (self.delegate = = nil) return;
2-remover All Subviews
[Scroller.subviews enumerateobjectsusingblock:^ (id obj, Nsuinteger idx, BOOL *stop) {
[obj Removefromsuperview];
}
3-xvalue is the starting point of the views inside the Scroller
CGFloat xvalue = Views_offset;
for (int i=0; i<[self.delegate numberofviewsforhorizontalscroller:self]; i++) {
4-add A view at the right position
Xvalue + = view_padding;
UIView *view = [self.delegate horizontalscroller:self viewatindex:i]
View.frame = CGRectMake (Xvalue, view_padding, View_dimensions, view_dimensions);
Xvalue + + view_dimensions + view_padding;
}
5
[Scroller Setcontentsize:cgsizemake (Xvalue+views_offset, self.frame.size.height)];
6-if an initial view are defined, center the scroller on it
if (self.delegate respondstoselector: @select (Initialviewindexforhorizontalscroller:)]) {
int initialview = [Self.delegate initialviewindexforhorizontalscroller:self];
[Scroller Setcontentoffset:cgpointmake (initialview* (view_dimensions+ (2*view_padding)), 0) Animated:YES];
}
}
Can go through the code step-by-step discussion:
If there is no agent, there is nothing to do here.
Remove all child views that were previously added.
Sets an offset position for all views. Now it's 100, but through the top #define it's easy to modify.
Horizontalscroller requests one view at a time through its delegate, placing them in sequence with the previously defined padding values.
When all the views are generated, set the offset of the scrolling view content so that the user can scroll to see all album cover purposes.
Horizontalscroller delegates need to verify that the Initialviewindexforhorizontalscroller: method is responding. This validation is required because this particular protocol method is optional. If the agent does not execute this method, its default value will be 0. Eventually, by delegating, this code sets an initialized view in the middle of the scrolling view.
Executes the reload method when the data changes. You can also perform this method when adding Horizontalscroller to a single view. In HORIZONTALSCROLLER.M Add the following code to replace the subsequent scenario:
Copy Code code as follows:
-(void) Didmovetosuperview
{
[Self reload];
}
When it wants to add a child view, Didmovetosuperview sends a message to the view. This is the right time to update the contents of the scrolling view.
The last problem with Horizontalscroller is how to set the album you see Always in the middle of the scrolling view. For these, you need to do some calculations when the user drags the scrolling view through their fingers.
Add the following method (same in HORIZONTALSCROLLER.M):
Copy Code code as follows:
-(void) Centercurrentview {
int xfinal = Scroller.contentoffset.x + (VIEWS_OFFSET/2) + view_padding;
int viewindex = xfinal/(view_dimensions + (2*view_padding));
xfinal = ViewIndex * (view_dimensions+ (2*view_padding));
[Scroller setcontentoffset:cgpointmake (xfinal, 0) Animated:yes];
[Self.delegate horizontalscroller:self Clickedviewatindex:viewindex];
}
The code above calculates the distance from the center of the current view by scrolling through the current offset of the view, the appearance dimensions, and the inner margin. The last line is important: When a view is centered, you need to notify the delegate that the view you selected has changed.
To detect a user's drag-and-drop action in a scrolling view, you need to add a Uiscrollviewdelegate method:
Copy Code code as follows:
-(void) scrollviewdidenddragging: (Uiscrollview *) ScrollView willdecelerate: (BOOL) decelerate
{
if (!decelerate)
{
[Self centercurrentview];
}
}
-(void) scrollviewdidenddecelerating: (Uiscrollview *) ScrollView
{
[Self centercurrentview];
}
When the user completes the drag scrollviewdidenddragging:willdecelerate: Notifies the delegate. If the scrolling view does not stop scrolling, the decelerate parameter returns TRUE. When scrolling finishes, the system will call scrollviewdidenddecelerating. When the user drags the current view in both cases, we need to call a new method to center the current view.
Horizontalscroller can now be used. Browse the code you just wrote; there is no mention of the Album and Albumview classes. This is great, to show that this new scrolling view is truly completely self-contained and reusable.
Build project to make sure all the code compiles correctly.
Now that the Horizontalscroller is done, it's time to use it in your APP. Open VIEWCONTROLLER.M Add the following reference:
Copy Code code as follows:
#import "HorizontalScroller.h"
#import "AlbumView.h"
Add Horizontalscrollerdelegate to Viewcontroller:
Copy Code code as follows:
@interface Viewcontroller () <uitableviewdatasource, Uitableviewdelegate, horizontalscroller>
Add the following instance variables to the horizontal scrolling view in the extension of the class:
Copy Code code as follows:
Horizontalscroller *scroller;
Now you can execute the proxy method; you'll be amazed at how many lines of code you'll be able to implement.
Add the following code to the VIEWCONTROLLER.M:
Copy Code code as follows:
#pragma mark-horizontalscrollerdelegate methods
-(void) Horizontalscroller: (Horizontalscroller *) scroller clickedviewatindex: (int) index
{
Currentalbumindex = index;
[Self showdataforalbumatindex:index];
}
Here set a variable to store the current album, and then call Showdataforalbumatindex: Display the data for a new album.
Tip: Generally place the #pragma mark indicator before the method code. The compiler ignores this line, and when you view your list of methods using the Xcode Jump Toolbar (Xcode ' Jump bar), you see a separator and a bold caption. In Xcode, this can help you organize your code very easily.
Next, add the following code:
Copy Code code as follows:
-(Nsinteger) Numberofviewsforhorizontalscroller: (Horizontalscroller *) scroller
{
return allalbums.count;
}
Here, the protocol method returns the number of views in the scrolling view. Because the scrolling view needs to display all album covers, this count is the number of all albums.
Now, add the code:
Copy Code code as follows:
-(UIView *) Horizontalscroller: (Horizontalscroller *) scroller viewatindex: (INI) index
{
Album *album = Allalbums[index];
return [[Album alloc] Initwithframe:cgrectmake (0, 0, MB) ALBUMCOVER:ALBUM.COVERURL];
}
Here you create a new albumview and give it to horizontalscroller for use.
This is how you can display a beautiful scrolling view with three of such short methods.
In fact, you still need to create a real scrolling view and add it to your master, but before that, add the following method:
Copy Code code as follows:
-(void) Reloadscroller
{
Allalbums = [[Libraryapi sharedinstance] getalbums];
if (Currentalbumindex < 0) Currentalbumindex = 0;
else if (currentalbumindex >=allalbum.count) currentalbumindex = allalbum.count-1;
[Scroller Reload];
[Self showdatafroalbumatindex:currentalbumindex;
}
This method loads the album data from the Libraryapi and then displays the current picture based on the index value of the current view. If the index of the current view is less than 0, it means that the view is not currently selected, showing the first album in the list. Otherwise, the last album is displayed.
Now, before [self showdataforalbumindex:0] in Viewdidload, add the following code to initialize the scrolling view:
Copy Code code as follows:
Scroller = [[Horizontalscroller alloc] Initwithframe:cgrectmake (0, 0, Self.view.frame.size.width, 120)];
Scroller.backgroundcolor = [Uicolor colorwithred:0.24f greed:0.35f blue:0.49f alpha:1];
Scroller.delegate = self;
[Self.view Addsubview:scroller];
[Self reloadscroller];
The above code creates an instance of the Horizontalscroller, sets its background color and delegates, adds a scrolling view to the main master, and loads the album data on a child view of the scrolling view.
Tip: If a protocol becomes large and there are many ways to do it, you should consider dispersing them into a few small protocols. Uitableviewdelegate and Uitableviewdatasource are a good example, because they are all uitablveview agreements. When designing a protocol, it is best to have a name to boot a feature.
Build and run your project, and you'll see a new very awesome horizontal scrolling view:
Ah, well, wait. The horizontal scrolling view is already available, but where is the album cover?
By the right, you still don't have the code to perform the download picture function. You need to add a way to download the picture. To search all the interfaces of the LIBRARYAPI service, you need to add a new method here. Anyway, there are a few things to consider now:
Albumview did not work immediately through LIBRARYAPI. You did not add communication logic to the view.
For the same reason, Libraryapi did not know Albumview.
Libraryapi need to notify Albumview, once the cover download is complete, Albumview will show it.