[[email protected] master-slave]# redis-cli
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> set site blog.jboost.cn
OK
127.0.0.1:6379> get site
"blog.jboost.cn"
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=7001,state=online,offset=13364738,lag=1
slave1:ip=127.0.0.1,port=7002,state=online,offset=13364738,lag=0
...
127.0.0.1:6379> exit
[[email protected] master-slave]# redis-cli -p 7001
127.0.0.1:7001> auth 123456
OK
127.0.0.1:7001> get site
"blog.jboost.cn"
[[email protected] cluster]# redis-cli -p 7100 -c -a passw0rd
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:7100> set site blog.jboost.cn
-> Redirected to slot [9421] located at 127.0.0.1:7200
OK
127.0.0.1:7200> get site
"blog.jboost.cn"
127.0.0.1:7200>
注意添加 -c 参数表示以集群模式,否则报 (error) MOVED 9421 127.0.0.1:7200 错误, 以 -a 参数指定密码,否则报(error) NOAUTH Authentication required错误。
从上面命令看到key为site算出的slot为9421,落在7200节点上,所以有Redirected to slot [9421] located at 127.0.0.1:7200,集群会自动进行跳转。因此客户端可以连接任何一个节点来进行数据的存取。
Categories are an Objective-C language feature that let you add new methods to an existing class, much like C# extensions. However, do not confuse C# extensions with Objective-C extensions. Objective-C’s extensions are a special case of categories that let you define methods that must be declared in the main implementation block.
These are powerful features that have many potential uses. First, categories make it possible to split up a class’ interface and implementation into several files, which provides much-needed modularity for larger projects. Second, categories let you fix bugs in an existing class (e.g., NSString) without the need to subclass it. Third, they provide an effective alternative to the protected and private methods found in C# and other Simula-like languages.
Categories
A category is a group of related methods for a class, and all of the methods defined in a category are available through the class as if they were defined in the main interface file. As an example, take the Person class that we’ve been working with throughout this book. If this were a large project, Person may have dozens of methods ranging from basic behaviors to interactions with other people to identity checking. The API might call for all of these methods to be available through a single class, but it’s much easier for developers to maintain if each group is stored in a separate file. In addition, categories eliminate the need to recompile the entire class every time you change a single method, which can be a time-saver for very large projects.
Let’s take a look at how categories can be used to achieve this. We start with a normal class interface and a corresponding implementation:
// Person.h
@interfacePerson: NSObject
@interfacePerson: NSObject
@property(readonly) NSMutableArray* friends;
@property(copy) NSString* name;
- (void)sayHello;
- (void)sayGoodbye;
@end
// Person.m
#import "Person.h"
@implementationPerson
@synthesizename = _name;
@synthesizefriends = _friends;
-(id)init{
self= [superinit];
if(self){
_friends = [[NSMutableArrayalloc]init];
}
returnself;
}
- (void)sayHello {
NSLog(@"Hello, says %@.", _name);
}
- (void)sayGoodbye {
NSLog(@"Goodbye, says %@.", _name);
}
@end
Nothing new here-just a Person class with two properties (the friends property will be used by our category) and two methods. Next, we’ll use a category to store some methods for interacting with other Person instances. Create a new file, but instead of a class, use the Objective-C Category template. Use Relations for the category name and Person for the Category on field:
Creating the Person+Relations class
As expected, this will create two files: a header to hold the interface and an implementation. However, these will both look slightly different than what we’ve been working with. First, let’s take a look at the interface:
// Person+Relations.h
#import <Foundation/Foundation.h>
#import "Person.h"
@interfacePerson(Relations)
- (void)addFriend:(Person*)aFriend;
- (void)removeFriend:(Person*)aFriend;
- (void)sayHelloToFriends;
@end
Instead of the normal @interface declaration, we include the category name in parentheses after the class name we’re extending. A category name can be anything, as long as it doesn’t conflict with other categories for the same class. A category’s file name should be the class name followed by a plus sign, followed by the name of the category (e.g., Person+Relations.h ).
So, this defines our category’s interface. Any methods we add in here will be added to the original Person class at run time. It will appear as though the addFriend:, removeFriend:, and sayHelloToFriends methods are all defined in Person.h, but we can keep our functionality encapsulated and maintainable. Also note that you must import the header for the original class, Person.h. The category implementation follows a similar pattern:
// Person+Relations.m
#import "Person+Relations.h"
@implementationPerson(Relations)
- (void)addFriend:(Person*)aFriend {
[[selffriends]addObject:aFriend];
}
- (void)removeFriend:(Person*)aFriend {
[[selffriends]removeObject:aFriend];
}
- (void)sayHelloToFriends {
for(Person*friend in[selffriends]) {
NSLog(@"Hello there, %@!", [friendname]);
}
}
@end
This implements all of the methods in Person+Relations.h. Just like the category’s interface, the category name appears in parentheses after the class name. The category name in the implementation should match the one in the interface.
Also, note that there is no way to define additional properties or instance variables in a category. Categories have to refer back to data stored in the main class (friends in this instance).
It’s also possible to override the implementation contained in Person.m by simply redefining the method in Person+Relations.m. This can be used to monkey patch an existing class; however, it’s not recommended if you have an alternative solution to the problem, since there would be no way to override the implementation defined by the category. That is to say, unlike the class hierarchy, categories are a flat organizational structure-if you implement the same method in two separate categories, it’s impossible for the runtime to figure out which one to use.
The only change you have to make to use a category is to import the category’s header file. As you can see in the following example, the Person class has access to the methods defined in Person.h along with those defined in the category Person+Relations.h:
// main.m
#import <Foundation/Foundation.h>
#import "Person.h"
#import "Person+Relations.h"
intmain(intargc, constchar* argv[]) {
@autoreleasepool{
Person*joe = [[Personalloc]init];
joe.name= @"Joe";
Person*bill = [[Personalloc]init];
bill.name= @"Bill";
Person*mary = [[Personalloc]init];
mary.name= @"Mary";
[joesayHello];
[joeaddFriend:bill];
[joeaddFriend:mary];
[joesayHelloToFriends];
}
return0;
}
And that’s all there is to creating categories in Objective-C.
Protected Methods
To reiterate, all Objective-C methods are public-there is no language construct to mark them as either private or protected. Instead of using “true” protected methods, Objective-C programs can combine categories with the interface/implementation paradigm to achieve the same result.
The idea is simple: declare “protected” methods as a category in a separate header file. This gives subclasses the ability to “opt-in” to the protected methods while unrelated classes use the “public” header file as usual. For example, take a standard Ship interface:
// Ship.h
#import <Foundation/Foundation.h>
@interfaceShip: NSObject
- (void)shoot;
@end
As we’ve seen many times, this defines a public method called shoot. To declare a protected method, we need to create a Ship category in a dedicated header file:
// Ship_Protected.h
#import <Foundation/Foundation.h>
@interfaceShip(Protected)
- (void)prepareToShoot;
@end
Any classes that need access to the protected methods (namely, the superclass and any subclasses) can simply import Ship_Protected.h. For example, the Ship implementation should define a default behavior for the protected method:
// Ship.m
#import "Ship.h"
#import "Ship_Protected.h"
@implementationShip{
BOOL_gunIsReady;
}
- (void)shoot {
if(!_gunIsReady) {
[selfprepareToShoot];
_gunIsReady = YES;
}
NSLog(@"Firing!");
}
- (void)prepareToShoot {
// Execute some private functionality.
NSLog(@"Preparing the main weapon...");
}
@end
Note that if we hadn’t imported Ship_Protected.h, this prepareToShoot implementation would be a private method, as discussed in the Methods chapter. Without a protected category, there would be no way for subclasses to access this method. Let’s subclass the Ship to see how this works. We’ll call it ResearchShip:
// ResearchShip.h
#import "Ship.h"
@interfaceResearchShip: Ship
- (void)extendTelescope;
@end
This is a normal subclass interface-it should not import the protected header, as this would make the protected methods available to anyone that imports ResearchShip.h, which is precisely what we’re trying to avoid. Finally, the implementation for the subclass imports the protected methods and (optionally) overrides them:
// ResearchShip.m
#import "ResearchShip.h"
#import "Ship_Protected.h"
@implementationResearchShip
- (void)extendTelescope {
NSLog(@"Extending the telescope");
}
// Override protected method
- (void)prepareToShoot {
NSLog(@"Oh shoot! We need to find some weapons!");
}
@end
To enforce the protected status of the methods in Ship_Protected.h, other classes aren’t allowed to import it. They’ll just import the normal “public” interfaces of the superclass and subclass:
// main.m
#import <Foundation/Foundation.h>
#import "Ship.h"
#import "ResearchShip.h"
intmain(intargc, constchar* argv[]) {
@autoreleasepool{
Ship*genericShip = [[Shipalloc]init];
[genericShipshoot];
Ship*discoveryOne = [[ResearchShipalloc]init];
[discoveryOneshoot];
}
return0;
}
Since neither main.m, Ship.h, nor ResearchShip.h import the protected methods, this code won’t have access to them. Try adding a [discoveryOne prepareToShoot] method-it will throw a compiler error, since the prepareToShoot declaration is nowhere to be found.
To summarize, protected methods can be emulated by placing them in a dedicated header file and importing that header file into the implementation files that require access to the protected methods. No other files should import the protected header.
While the workflow presented here is a completely valid organizational tool, keep in mind that Objective-C was never meant to support protected methods. Think of this as an alternative way to structure an Objective-C method, rather than a direct replacement for C#/Simula-style protected methods. It’s often better to look for another way to structure your classes rather than forcing your Objective-C code to act like a C# program.
Caveats
One of the biggest issues with categories is that you can’t reliably override methods defined in categories for the same class. For example, if you defined an addFriend: class in Person(Relations) and later decided to change the addFriend: implementation via a Person(Security) category, there is no way for the runtime to know which method it should use since categories are, by definition, a flat organizational structure. For these kinds of cases, you need to revert to the traditional subclassing paradigm.
Also, it’s important to note that a category can’t add instance variables. This means you can’t declare new properties in a category, as they could only be synthesized in the main implementation. Additionally, while a category technically does have access to its classes’ instance variables, it’s better practice to access them through their public interface to shield the category from potential changes in the main implementation file.
Extensions
Extensions (also called class extensions) are a special type of category that requires their methods to be defined in the main implementation block for the associated class, as opposed to an implementation defined in a category. This can be used to override publicly declared property attributes. For example, it is sometimes convenient to change a read-only property to a read-write property within a class’ implementation. Consider the normal interface for a Ship class:
Included code sample: Extensions
// Ship.h
#import <Foundation/Foundation.h>
#import "Person.h"
@interfaceShip: NSObject
@property(strong, readonly) Person*captain;
- (id)initWithCaptain:(Person*)captain;
@end
It’s possible to override the @property definition inside of a class extension. This gives you the opportunity to re-declare the property as readwrite in the implementation file. Syntactically, an extension looks like an empty category declaration:
// Ship.m
#import "Ship.h"
// The class extension.
@interfaceShip()
@property(strong, readwrite) Person*captain;
@end
// The standard implementation.
@implementationShip
@synthesizecaptain = _captain;
- (id)initWithCaptain:(Person*)captain {
self= [superinit];
if(self) {
// This WILL work because of the extension.
[selfsetCaptain:captain];
}
returnself;
}
@end
Note the () appended to the class name after the @interface directive. This is what marks it as an extension rather than a normal interface or a category. Any properties or methods that appear in the extension must be declared in the main implementation block for the class. In this case, we aren’t adding any new fields-we’re overriding an existing one. But unlike categories, extensions can add extra instance variables to a class, which is why we’re able to declare properties in a class extension but not a category.
Because we re-declared the captain property with a readwrite attribute, the initWithCaptain: method can use the setCaptain: accessor on itself. If you were to delete the extension, the property would return to its read-only status and the compiler would complain. Clients using the Ship class aren’t supposed to import the implementation file, so the captain property will remain read-only.
// This will NOT work because the property is still read-only.
[discoveryOnesetCaptain:dave];
}
return0;
}
Private Methods
Another common use case for extensions is for declaring private methods. In the previous chapter, we saw how private methods can be declared by simply adding them anywhere in the implementation file. But, prior to Xcode 4.3, this was not the case. The canonical way to create a private method was to forward-declare it using a class extension. Let’s take a look at this by slightly altering the Ship header from the previous example:
// Ship.h
#import <Foundation/Foundation.h>
@interfaceShip: NSObject
- (void)shoot;
@end
Next, we’re going to recreate the example we used when we discussed private methods in the Methods chapter. Instead of simply adding the private prepareToShoot method to the implementation, we need to forward-declare it in a class extension.
// Ship.m
#import "Ship.h"
// The class extension.
@interfaceShip()
- (void)prepareToShoot;
@end
// The rest of the implementation.
@implementationShip{
BOOL_gunIsReady;
}
- (void)shoot {
if(!_gunIsReady) {
[selfprepareToShoot];
_gunIsReady = YES;
}
NSLog(@"Firing!");
}
- (void)prepareToShoot {
// Execute some private functionality.
NSLog(@"Preparing the main weapon...");
}
@end
The compiler ensures the extension methods are implemented in the main implementation block, which is why it functions as a forward-declaration. Yet because the extension is encapsulated in the implementation file, other objects shouldn’t ever know about it, giving us another way to emulate private methods. While newer compilers save you this trouble, it’s still important to understand how class extensions work, as it has been a common way to leverage private methods in Objective-C programs until very recently.
Summary
This chapter covered two of the more unique concepts in the Objective-C programming language: categories and extensions. Categories are a way to extend the API of existing classes, and extensions are a way to add required methods to the API outside of the main interface file. Both of these were initially designed to ease the burden of maintaining large code bases.
The next chapter continues our journey through Objective-C’s organizational structures. We’ll learn how to define a protocol, which is an interface that can be implemented by a variety of classes.
sortInts = someInts.sorted(by: {a,b in a > b})
print(sortInts)
2.4.使用参数名缩写(不推荐使用)
Swift 自动为内联闭包提供了参数名称缩写功能,你可以直接通过$0,$1,$2 来顺序调用闭包的参数,以此类推。
如果我们在闭包表达式中使用参数名称缩写, 我们就可以在闭包定义中省略参数列表,并且对应参数名称缩写的类型会通过函数类型进行推断。in关键字也同样可以被省略,因为此时闭包表达式完全由闭包函数体构成:
if __name__ == '__main__':
server = tornado.httpserver.HTTPServer(app)
server.listen(5050)
tornado.httpclient.AsyncHTTPClient.configure("tornado.curl_httpclient.CurlAsyncHTTPClient")
tornado.ioloop.IOLoop().instance().start()
然后我们请求5050端口的服务,也连接发送两次http请求:
(venv)☁ keepalive curl http://127.0.0.1:5050/async/keepalive It works% (venv)☁ keepalive curl http://127.0.0.1:5050/async/keepalive It works%
def TestKillAndTerminate():
p=subprocess.Popen(“notepad.exe”)
t = 1
while(t <= 5):
time.sleep(1)
t +=1
p.kill()
#p.terminate()
print (“new process was killed”)
if p.returncode != 0:
print (cmd + “error !”)
#defaultly the return stdoutdata is bytes, need convert to str and utf8
for r in str(stdoutdata,encoding=’utf8′ ).split(“\n”):
print (r)
print (p.returncode)
def TestCommunicate2():
import subprocess
cmd = “dir”
#universal_newlines=True, it means by text way to open stdout and stderr
p = subprocess.Popen(cmd, shell=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
curline = p.stdout.readline()
public class Person {
private String name;
private int age;
private Person sponse;
private Person[] children;
// setXXX, getXXX方法略.
}
现在让我们装配一个Jone:
Person john = new Person();
john.setAge(37);
john.setName("John Smith");
Person sponse = new Person();
sponse.setName("Jane Smith");
sponse.setAge(25);
john.setSponse(sponse);
Person[] children = {new Person(), new Person()};
children[0].setName("Jimmy Smith");
children[0].setAge(15);
children[1].setName("Jenny Smith");
children[1].setAge(12);
john.setChildren(children);
使用JYaml把Jone“Dump”出来:
File dumpfile = new File("John_dump.yaml");
Yaml.dump(john, dumpfile);
下面我们看看John_dump.yaml是什么样子:
--- !yaml.test.internal.Person
age: 37
children: !yaml.test.internal.Person[]
- !yaml.test.internal.Person
age: 15
name: Jimmy Smith
- !yaml.test.internal.Person
age: 12
name: Jenny Smith
name: John Smith
sponse: !yaml.test.internal.Person
age: 25
name: Jane Smith
其中!yaml.test.internal.Person是一些类型的信息。load的时候需要用。
现在用JYaml把Jone_dump.yaml load进来:
Person john2 = (Person) Yaml.loadType(dumpfile, Person.class);
YamlDecoder dec = new YamlDecoder(new FileInputStream(dumpfile));
int age = 37;
while(true){
try{
john = (Person) dec.readObject();
assertEquals(age, john.getAge());
age++;
}catch(EOFException eofe){
break;
}
}
class Person
attr_accessor :name, :age, :sponse, :children
def initialize(name, age, sponse=nil, children=nil)
@name = name
@age = age
@sponse = sponse
@children = children
end
end
把John装配起来:
jane = Person.new("Jane Smith", 25)
children = [Person.new("Jimmy Smith", 15), Person.new("Jenny Smith", 12)]
john = Person.new("John Smith", 37, jane, children)
Dump出John到John.yaml:
File.open('John_ruby.yaml', 'w') do |os|
YAML::dump(john, os)
end
我们看看Dump的结果:
--- !ruby/object:Person
age: 37
children:
- !ruby/object:Person
age: 15
children:
name: Jimmy Smith
sponse:
- !ruby/object:Person
age: 12
children:
name: Jenny Smith
sponse:
name: John Smith
sponse: !ruby/object:Person
age: 25
children:
name: Jane Smith
sponse: