古琴F调按音图

古琴F调按音图
古琴F调按音图

各弦音域(散音加徽内按音)

  • 一弦: 5– 到 5+
  • 二弦: 6– 到 6+
  • 三弦: 1- 到 1++
  • 四弦: 2- 到 2++
  • 五弦: 3- 到 3++
  • 六弦: 5- 到 5++
  • 七弦: 6- 到 6++

所以古琴的音域是很广的,从5–到6++,总共4个八度多一点。
每根弦的按音最高就是一徽按音,一徽是弦长的 1/8,所以一徽按音比散音高3个8度。

各个音的位置

  • 5– : 一弦散音
  • 6– : 二弦散音,一弦十三徽
  • 7– : 二弦十三徽, 一弦十徽八分
  • 1- : 三弦散音, 二弦十二徽, 一弦十徽
  • 2- : 四弦散音, 三弦十三徽, 二弦十徽, 一弦九徽
  • 3- : 五弦散音, 四弦十三徽, 三弦十徽八分, 二弦九徽, 一弦七徽九分
  • 4- : 四弦十二徽, 三弦十徽, 二弦八徽五分, 一弦七徽六分
  • 5- : 六弦散音, 五弦十二徽, 四弦十徽, 三弦九徽, 二弦七徽六分, 一弦七徽
  • 6- : 七弦散音, 六弦十三徽, 五弦十徽, 四弦九徽, 三弦七徽九分, 二弦七徽, 一弦六徽四分
  • 7- : 七弦十三徽, 六弦十徽八分, 五弦九徽, 四弦七徽九分, 三弦七徽三分, 二弦六徽四分, 一弦六徽
  • 1 : 七弦十二徽, 六弦十徽, 五弦八徽五分, 四弦七徽六分, 三弦七徽, 二弦六徽二分, 一弦五徽六分
  • 2 : 七弦十徽, 六弦九徽, 五弦七徽六分, 四弦七徽, 三弦六徽四分, 二弦五徽六分, 一弦五徽
  • 3 : 七弦九徽, 六弦七徽九分, 五弦七徽, 四弦六徽四分, 三弦六徽, 二弦五徽, 一弦四徽六分
  • 4 : 七弦八徽五分, 六弦七徽六分, 五弦六徽七分, 四弦六徽二分, 三弦五徽六分, 二弦四徽八分, 一弦四徽四分
  • 5 : 七弦七徽六分, 六弦七徽, 五弦六徽二分, 四弦五徽六分, 三弦五徽, 二弦四徽四分, 一弦四徽
  • 6 : 七弦七徽, 六弦六徽四分, 五弦五徽六分, 四弦五徽, 三弦四徽六分, 二弦四徽, 一弦三徽四分
  • 7 : 七弦六徽四分, 六弦六分, 五弦五分, 四弦六徽四分, 三弦四徽二分, 二弦三徽四分, 一弦三徽
  • 1+ : 七弦六徽二分, 六弦五徽六分, 五弦四徽八分, 四弦四徽四分, 三弦四徽, 二弦三徽二分, 一弦二徽六分
  • 2+ : 七弦五徽六分, 六弦五徽, 五弦四徽四分, 四弦四徽, 三弦三徽四分, 二弦二徽六分, 一弦二徽
  • 3+ : 七弦五徽, 六弦四徽六分, 五弦四徽, 四弦三徽四分, 三弦三徽, 二弦二徽, 一弦一徽六分
  • 4+ : 七弦四徽八分, 六弦四徽四分, 五弦三徽八分, 四弦三徽二分, 三弦二徽六分, 二弦一徽八分, 一弦一徽四分
  • 5+ : 七弦四徽四分, 六弦四徽, 五弦三徽二分, 四弦二徽六分, 三弦二徽, 二弦一徽四分, 一弦一徽
  • 6+ : 七弦四徽, 六弦三徽四分, 五弦二徽六分, 四弦二徽, 三弦一徽六分, 二弦一徽
  • 7+ : 七弦三徽四分, 六弦三徽, 五弦二徽, 四弦一徽六分, 三弦一徽二分
  • 1++ : 七弦三徽二分, 六弦二徽六分, 五弦一徽八分, 四弦一徽四分, 三弦一徽
  • 2++ : 七弦二徽六分, 六弦二徽, 五弦一徽四分, 四弦一徽
  • 3++ : 七弦二徽, 六弦一徽六分, 五弦一徽
  • 4++ : 七弦一徽八分, 六弦一徽四分
  • 5++ : 七弦一徽四分, 六弦一徽
  • 6++ : 七弦一徽

Cron

Cron在Linux系统中用于计划任务。

举个例子

0 */2 * * * date >> /var/log/date.log

这将在每2小时往date.log里记录下date命令的结果。

格式说明

前面5位数,分别代表的是 分钟 小时 日 月 星期几, 然后后面就是条件满足时候运行的命令。
这前面5位数,可取值的范围是:
逗号 (‘,’) 分开的值,例如:“1,3,4,7,8”
连词符 (‘-‘) 制定值的范围,例如:“1-6”,意思等同于“1,2,3,4,5,6”
星号 (‘‘) 代表任何可能的值。例如,在“小时域” 里的星号等于是“每一个小时”
斜杠 (‘/’) 代表整除,例如”
/2″表示所有的偶数

参考

http://zh.wikipedia.org/wiki/Cron

十二平均律

简介

十二平均律是音乐定调的基本方法,是指将一个八度,(频率相差1倍),的范围,平均分成12分(等比)。每一段叫做一个半音,两个叫做全音。然后将我们常见的do, re, mi, fa, so, la, xi分布在这上面。
除了mi-fa和xi到高八度的do两个半音以外,其它间距都是全音,这样正好凑成12个半音。
半音的频率比就是 2^(1/12)
现在的钢琴就是这么调的,相邻键之间是半音。

?

为什么这么搞呢?因为这样定调之后,无论do的频率是多少,演奏出来的感觉是旋律不会变。

参考

百度百科的解释,后面的部分看着比较有意思,不想重复了。

Using VCR with WebMock in Rails Rspec Tests

If the application need interaction with another web service, it’s convenience to using VCR with WebMock to test the application, rather than doing the request to another web service every time.

Setup

Modify Gemfile

group :test do
  gem 'webmock'
  gem 'vcr'
end

and don’t forget to run

bundle install

Config VCR

The following code can be placed in the spec_helper.rb

VCR.configure do |c|
  c.allow_http_connections_when_no_cassette = true
  c.cassette_library_dir = 'spec/cassettes' #this specified the directory for placing the record files
  c.hook_into :webmock
  c.configure_rspec_metadata!
  c.default_cassette_options = {
    :record => :once,
    :erb => true,
    :match_requests_on => [:method, :uri, :host, :path, :headers]
  }
end

Using VCR

Then you can using VCR when write the rspec test like:

describe 'Some api call tests', :vcr => true do
#write normal api call tests here
end

Re-record

Sometimes we need to re-record the cassettes, because maybe the request params changed in our app or the response is updated from third-party server.

It’s very easy to do that, just modify your VCR.config block, set record: all instead of :once.

:record => :all

and run your rspec tests related to that cassettes, then the cassettes files will be updated.

And you can specify the matchers per test:

describe 'Something', :vcr => {match_requests_on:[:method, :uri]} do
  # Some tests
end

The following method can tell whether vcr is recording, it’s very useful in some scenarios:

VCR.current_cassette.recording?

[Repost] Here Document in Ruby

This is repost from http://log.gmarik.info/2007/12/rubys-here-document-heredoc-mini.html , good post!

Basics

Here Document(or HereDoc) is a way to declare String literal in Ruby programming language:

some_text = <<END_OF_STRING
 You can write any text here for your document that's why such
 statement is called - HereDoc
END_OF_STRING

That’s it! Now some_text variable points to the string object containing the text going between END_OF_STRING
As you may know HereDoc isn’t a unique Ruby feature, rather it’s a common construct(with some distinctions) for scripting languages “brewed” in Unix environment.

The terminator

By Ruby convention a variable starting with capital letter is a constant. But that’s not a case for the END_OF_STRING from previous example, because terminator is just a string which parser treats as the end of HereDoc.
Well if a terminator is a string then can i use arbitrary(say put spaces within) string as the terminator like end of string? The answer is – yes you can!
<<heredoc is interpreted same as <<"heredoc" (please note double quotes around latter heredoc).
But explicit notation(with quotes) is a bit more powerful.

String interpolation

By explicitly enclosing terminator with quotes you may have:

a_text = <<"Ruby, please end my HereDoc once you find this terminator string"
Hello world!
Ruby, please end my HereDoc once you find this terminator string

or

fuzzy_names = <<">>"
foo, baz, bar
>>

Wow, if i can use double quoted string, then probably i can use single quoted string as well:

puts <<'end of string'
 1+1=#{1+1}
end of string
prints
1+1=#{1+1}

as single quoted strings aren’t interpolated unlike double quoted:

puts <<"end of string"
 1+1=#{1+1}
end of string
prints
1+1=2

Indent modifier

By default HereDoc terminator is expected to be placed on the very beginning of the separate line
By using – on HereDoc declaration, you may indent end terminator arbitrary:

greeting = <<-"here document ends"
                 Hello world
               here document ends

Keep in mind that leading spaces are kept.

Advanced usages

a, b = <<'EOA', <<-EOB
string_a
EOA
string_b
   EOB
is equal to
a, b = "string_a\n", "string_b\n"

At this point i’m thinking about HereDoc as “placeholder” that gets substituted with the string itself. Why is that important? Because you may then treat HereDoc declaration as the actual string and send messages(call methods):

<<'heredoc'.reverse == "\n!dlrow olleH"
Hello world!
heredoc

is a true statement!

[Repost]How to kill a dragon with various programming languages

Repost from How to kill a dragon with various programming languages


This funny text comes from Ibon from the dream team who got it from a Spanish blog.

There’s a beautiful princess, prisoner in the highest tower of a castle, guarded by a mighty dragon, and a fearless knight must rescue her…

This is how each language would manage to rescue the princess from the hands of the dragon

Java – Gets there, finds the dragon, develops a framework for dragon anihilation with multiple layers, writes several articles about the framework… But doesn’t kill the dragon.
.NET – Gets there, sees the idea of the Java developer and copies it. Tries to kill the dragon, but the monster eats him.
C – Arrives, looks down at the dragon, pulls out his sword, beheads the dragon, finds the princess… And ignores her to see the last checkins of linux kernel cvs.
C++ – Creates a basic needle, and gathers funcionality until he has a complex sword that he can barely understand… He kills the dragon, but gets stuck crossing the bridge because of memory leaks.
COBOL – Arrives, sees the dragon and thinks that he is too old to kill a monster that big and rescuing the princess, so he leaves.
Pascal – He prepares for 10 years to create a dragon anihilation system… When the moment comes, he discovers the program can only take lizards as an entry.
VB – Builds a dragon destruction weapon based on several components, jumps to the back of the dragon and in the most critical time he discovers that the sword works only on rainy nights…
PL/SQL – Gets data from other dragon slayers, creates tables with n ternary complexity relations, tridimensional data, OLAP, takes 15 years to process the information… And by then, the princess became a lesbian.
Ruby – Arrives with massive fame, saying he is the best at anything and when he faces the dragon, he shows a lame motion picture of himself killing a dragon… The dragon eats him out of boredom.
Smalltalk – Arrives, analyzes the dragon and princess, turns around and leaves, they are way too inferior.
shell – Creates a very powerful dragon slaying weapon… But in the moment of truth, he can’t remember how to use it.
shell(2)- The guy approaches the dragon with a two line script that kills, cuts, disembowels, impales, chops to pieces and packs the beast, but when he runs it the script grows, it fattens, irritates and puts alcohol in the fire of the dragon…
Assembler – He thinks he’s doing the right and most efficient things… But he writes an A instead of a D and kills the princess to end up f***ing the dragon.
Fortran – Arrives and develops a 45-thousand-code-line-solution, kills the dragon, meets the princess… But she calls him a weakling and runs after the Java programmer who was elegant, and also rich.
FOX PRO – Develops a dragon killing system. It’s gorgeous and works on the outside, but it’s really patched inside, so when he runs the dragon anihilator, he realizes he forgot to index the DBFs.
PROCESS ANALYST – Approaches the dragon with two tons of documentation, develops the unified dragon-killing process, he develops a DFD to free the princess and marry her, convinces the dragon that it’s the best for him and it won’t hurt. When he executes the process, he estimates the effort and the damage he will cause with a plan signed by the Pope, Buddha and Michael Jackson. Then he buys a couple of nukes, 45 cannons, an aircraft carrier and hires 300 heavily armed men… When all he needed was the sword he was holding in his hand in the beginning…
CLIPPER: Sets up a routine that loads a codeblock array to insult the dragon, serenade the princess, load the sword in memory, beat the crap out of the dragon, clean the mess, prepare a raspberry milkshake for the princess, make love to her, take a bath, start the car, put it some gas and come back home. When he runs it, he gets a “Bound Error: Array Access” and the dragon eats him with fries.
Lisp, where the famous knight-errant, after speaking with numerous experts in dragon-killing, and modeling the knowledge they posess, he programs the system, and when he runs it he realizes he forgot a bracket (bender the offender).
HTML: Mounts a web on famous swords used to kill dragons, but he ignores the W3C standards. When he meets the dragon, he finds out the code isn’t compatible with his browser, so he’s left swordless. The dragon eats him as an appetizer.
Prolog: Thinks he needs a weapon to kill the dragon. Searches in a catalog for 182014 weapons. By the time the princess dies of her age, he’s achieved to know how to make every weapon starting with A: Atomic Bombs, Anti-Air Weapons, Arches, Ammunition, Axes…
PHP: Creates a web page that when he executes it would eliminate the $dragon selecting from a weapons databese in MySQL over an Apache server. Nevertheless he forgot the WHERE in the DELETE query and kills the princess, the dragon, the peasants, the witch, the sorceror and the programmer himself.
JavaScript: The programmer tries to kill the great green dragon that spits fire throug his mouth. He creates a script that will delete the dragon when he loads a webpage, to create seconds after, some damsels to throw him flowers and make clapping sounds. Unfortunately he didn’t take into account the DOM structure of the lizard, also known as Mozilla, and the only thing he gets is to fill his console of errors and that the Book of Mozilla tells how he was devoured.
ActiveX: The programmers create a tunnel to enter the dragon’s lair from the castle and run a program that will kil the dragon from a safe and prudential distance. The dragon discovers the tunnel, eats the workers who dug, the dragon slayers, and enslaves every servant in the castle. The castle becomes a dragon-breeding place, full of little dragons that the dragon sends in pop-ups to other castles. The untasty remains of the knights are put in cans of Spam and sent to other castles as well as a warning. (aquelquesiente)
Basic. He creates a weapon able to kill paper dragons, but no matter how they improve it, they discover it’s not good enough to kill any dragon bigger than a baby poodle.
Matlab: They create a loop that calculates the trajectories to shoot a giant arrow at the dragon. The program works flawlessly. What they need now are the voluntaries caoable to launch tha arrow with the necessary strength and accuracy.
Videogame Programmer : Spends two years programming a state-of-the-art sword with shaders and all. When the time comes to kill the dragon, he finds that half the knights aren’t strong enough to raise the sword. Then someone programs a patch that reveals the sex scenes with the princess and Hillary Clinton makes it a scandal.

SOAP Protocol

SOAP – Simple object access protocol, based on the HTTP, using in the information transferring between endpoints on the Internet.
SOAP – 简单对象存取协议,基于HTTP,是一个用来在Internet上传输信息的标准

SOAP package from sender (发送方的例子)

The package from sender in like below:
发送方的代码如下:

<?xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">

<soap:Header>
  ...
  ...
</soap:Header>

<soap:Body>
  ...
  ...
  <soap:Fault>
    ...
    ...
  </soap:Fault>
</soap:Body>

</soap:Envelope>

The namespaces and the Envelope in the example are forced to be present. the Header is optional.
其中命名空间和Envelop标签都是必须的,Header标签是可选的。
In the Body, the sender can have what ever it want to be there, but must follow the XML rules.
在Body标签中,应用程序可以放入其需要传输的任何内容。

The response from receiver (接收方的反馈)

<?xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">

<soap:Body>
   <m:GetPriceResponse xmlns:m="http://www.w3school.com.cn/prices">
      <m:Price>1.90</m:Price>
   </m:GetPriceResponse>
</soap:Body>

</soap:Envelope>

In this manner, the endpoints exchange informations through internet.
终端之间就是通过这种简单的方式进行数据传输的。

Using in Ruby – SOAP4R (Ruby中的gem – SOAP4R)

http://www.tutorialspoint.com/ruby/ruby_web_services.htm

Reference (参考)

http://w3school.com.cn/soap/index.asp

STI of ActiveRecord in Rails

STI, Single Table Inheritance, supported by ActiveRecord in rails to let us build the models’ hierarchy on a single data table.

Model description

For example, we have a User model, and have an Administrator model, which inherit from User. we can build just one table named ‘user’, and make sure there is a column named ‘type’ and of string type in the User table. like below:

mysql>describe 'user';
+--------------------------+--------------+------+-----+----------+----------------+
| Field                    | Type         | Null | Key | Default  | Extra          |
+--------------------------+--------------+------+-----+----------+----------------+
| id                       | int(11)      | NO   | PRI | NULL     | auto_increment |
| type                     | varchar(255) | YES  |     | NULL    |                |
| name                     | varchar(255) | YES  |     | NULL     |                |
+--------------------------+--------------+------+-----+----------+----------------+

Code

then, we can writing following code to have a look of STI:

class User < ActiveRecord::Base
    validates_presence_of :name
end
class Administrator < Post
end

just this, and we can verify it in console:

admin = Administrator.create( :name => "admin")
admin.type # "Administrator"
admin.id # 1

Concerns

the STI is enabled by default, and so the 'type' in table is likely reserved for STI and we can not using it for other purpose;
and another problem is that if the shared columns are not so much in the model hierarchy, it's a waste using STI, we prefer to setup another table for the child model.
Luckily, we can disable this feature in a table that not using this feature. by doing this:

class User < ActiveRecord::Base
    self.abstract_class = true
    validates_presence_of :name
end
class Administrator < Post
end

by doing this, the 'type' columns in User can be used at our will and there must another table for Administrator alone.

Referrence

http://ihower.tw/rails3/activerecord-others.html

The difference from %w to %W in Ruby

Difference between %w and %W

In short, %w act as ', while %W act as "
In long words, %w not convert the #{} clause, but %W do, like the codes below:

Code

irb(main):001:0> foo="hello"
=> "hello"
irb(main):002:0> %W(foo bar baz #{foo})
=> ["foo", "bar", "baz", "hello"]
irb(main):003:0> %w(foo bar baz #{foo})
=> ["foo", "bar", "baz", "\#{foo}"]

Reference

http://stackoverflow.com/questions/690794/ruby-arrays-w-vs-w

Typhoeus : a gem for http requests in rails.

Typhoeus



Single request

request = Typhoeus::Request.new(
  "www.example.com",
  method: :post,
  body: "this is a request body",
  params: { field1: "a field" },
  headers: { Accept: "text/html" }
)

# handle the response as follows
request.on_complete do |response|
  if response.success?
    # hell yeah
  elsif response.timed_out?
    # aw hell no
    log("got a time out")
  elsif response.code == 0
    # Could not get an http response, something's wrong.
    log(response.return_message)
  else
    # Received a non-successful http response.
    log("HTTP request failed: " + response.code.to_s)
  end
end

# this will actually execute the request
request.run



Parallel requests
Typhoeus doing well in the parallel requests, just doing this:

hydra = Typhoeus::Hydra.hydra

first_request = Typhoeus::Request.new("www.example.com/posts/1.json")
first_request.on_complete do |response|
  third_request = Typhoeus::Request.new(www.example.com/posts/3.json)
  hydra.queue third_request
end
second_request = Typhoeus::Request.new("www.example.com/posts/2.json")

hydra.queue first_request
hydra.queue second_request
# this is a blocking call that returns once all requests are complete
hydra.run



Referrence
For more information, looking:
Typhoeus on Github

How to customize screen resolution in windows7 with ATI graphics card

Recently, I brought a Dell U2713HM display, with resolution of 2560 * 1440. And my current computer have a HD6800 ATI card.

Then when I connect display with DVI cable, it turns out that the highest resolution I can set is 1920 * 1200 in the windows settings. That’s sucks.

So after tried a lot of solutions, there is one works!


first, unlock the pixel clock of grahpics card, using:
http://www.monitortests.com/forum/Thread-AMD-ATI-Pixel-Clock-Patcher
atikmdag-patcher-1.2

second, specify your custom resolution using CRU:
http://www.monitortests.com/forum/Thread-Custom-Resolution-Utility-CRU
cru-1.1

Great thanks to the authors of those softwares!!

Less

Zete says: “Less is more”


Color: export LESS=’–raw-control-chars –quiet –LINE-NUMBERS –HILITE-UNREAD –ignore-case –long-prompt’
F: go to end of file and waiting new data
ctrl + f / space: page down
ctrl + b: page up

How to save image data with exif information from UIImagePickerController

The UIImage returned from UIImagePickerController is without exif information, if we want generate an NSData from it, saving to disk or sharing via network for example. We can mix the exif information into the NSData.

Like this:

- (NSData *)dataFromImage:(UIImage *)image metadata:(NSDictionary *)metadata mimetype:(NSString *)mimetype
{
    NSMutableData *imageData = [NSMutableData data];
    CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (__bridge CFStringRef)mimetype, NULL);
    CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, uti, 1, NULL);

    if (imageDestination == NULL)
    {
        NSLog(@"Failed to create image destination");
        imageData = nil;
    }
    else
    {
        CGImageDestinationAddImage(imageDestination, image.CGImage, (__bridge CFDictionaryRef)metadata);

        if (CGImageDestinationFinalize(imageDestination) == NO)
        {
            NSLog(@"Failed to finalise");
            imageData = nil;
        }
        CFRelease(imageDestination);
    }

    CFRelease(uti);

    return imageData;
}

and in the callback of UIImagePickerController, do this:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
    NSDictionary *metadata = [info objectForKey:UIImagePickerControllerMediaMetadata];
    NSString *mimeType = @"image/jpeg"; // ideally this would be dynamically set. Not defaulted to a jpeg!

    // you could add to the metadata dictionary (after converting it to a mutable copy) if you needed to.

    // convert to NSData
    NSData *imageData = [self dataFromImage:image metadata:metadata mimetype:mimeType];

    // ...
}

Referrence
http://stackoverflow.com/questions/15239719/convert-uiimage-to-nsdata-without-using-uiimagepngrepresentation-or-uiimagejpegr

如何安装三分区Mac和Windows双操作系统

分区情况
我装好系统后分区是这样的:
1.EFI,200M,保留分区,这个不用管。
2.Windows系统分区
3.FAT分区,用来做数据交换,Mac和Windows都能访问\
4.Mac系统分区
5.Mac Recovery,600M, 你会发现这个分区自动就出来了。

准备材料
1. Windows7安装盘(光盘,u盘,硬盘随意)
2. Mac OSX 10.8.4 安装盘(我是把镜像写入硬盘了)

第一步
开机按住Option键(windows键盘是alt,屏幕亮了再按),进入启动盘选择菜单。选择MacOSX安装盘启动。

第二步
启动后选择磁盘工具。
然后将硬盘分为3个分区,第一个是windos安装分区,第二个是交换分区,第三个是Mac安装分区。前两个格式化成Fat,第三个用Mac日志格式。

第三步
重启,还是选MacOsX安装盘,安装MacOSX在Mac分区上

第四步
Mac安装完成之后,如果你还没有Win7的安装盘,可以启动Bootcamp做一个。然后直接重启,也是开机按Option,然后选择Windows安装盘启动。将Windows安装在先前分配的Windows分区上。
这一步有个坑,就是如果你遇到了,“安装程序无法创建系统分区,也无法定位系统分区”错误,那是因为你同时插上了多个启动盘,把Mac安装盘,和其它除了Windows安装盘以外的USB驱动器都拔掉,然后点刷新。如果还不可以,就重启一下,这个问题就解决了。
如果你用搜索引擎搜到这篇文章,就算你运气了。我是搜索了好多的方法,但是没有一个奏效。直到我尝试安装Win8(只有英文版),得到了同样的”Setup was unable to create a new system partition or locate an existing system partition”错误,用google搜索才得到正确解决办法。

第五步
Windows安装完成之后,安装Bootcamp驱动程序

搞定

Using Github

git status

this is used for checking the status of local on the current branch.

git fetch origin aRemoteBranchName:targetLocalBranch

this will fetch the remote branch named aRemoteBranchName into local repo with branch name targetLocalBranch

git push origin aLocalBranch:targetRemoteBranch

this will push local branch aLocalBranch into the remote repo of the targetRemoteBranch, the :targetRemoteBranch can omitted if the branch name is the same as local branch.

Squash commits

//squash 3 commit into one, doing following:
git rebase -i HEAD~3
//in the coming edit, replace 'pick' to 's' for the following 2 commits, this will squash them into the first commit
//then 
git rebase --continue

Edit commit message

// a -> b -> c -> d
//to edit the commit message for d, doing following:
git commit --amend
//in the edit interface, just edit the commit message there

//if you want to edit the message for b, doing the following:
git rebase -i HEAD~3
//just save the coming text
//then the b becomes the last commit and c,d is disappeared temporarily
git commit --amend
//edit the message for b
//then rebase back
git rebase --continue

Mac下修改终端提示符

环境变量PS1中存放的就是终端提示符的格式,可以通过这个命令来查看:

echo $PS1

环境变量PS2是换行之后的提示符格式

可以使用的部分格式包括:

\d – 现在的系统日期

\t – 现在的系统时间

\h – 主机名

# – 命令号(Comannd Number)

\u – 用户名

\W – 当前所在的路径

\w – 当前所在的完整路径

我现在用的是这个:

\[\e[36;40m\]\w

NetStream.Read in C#

调用NetStream.Read(buffer, offset, len)有一个坑,那就是它一次读取并不一定会真正读完你指定的len长度,所以最好这么写:

    for (int alreadyRead = 0; alreadyRead < len; )
        alreadyRead += stream.Read(buffer, alreadyRead, len - alreadyRead);

为此浪费了不少时间·

Push Notification, Step by Step Setup.

坑爹的苹果,居然在提交证书的时候,由于浏览器(自家的Safari)的问题导致提交不成功,换成别的浏览器才成功。
The device token for Development and for Production is DIFFERENT!

(!!! DO NOT use the Safari, When access the develop.apple.com)
1.Access the certificate for push notification
1.获取用于推送通知的证书

1.1.Request 2 certificate from the KeyChain Assistant (CSR), one for develop, one for production. If you do not know how to do it, see Instruction 1.4 below. And export the associated Private Key as .p12 files. So after this step, we get 4 files.
1.1.从证书助手获取两个证书,一个在开发中使用,一个在发布的产品中使用(详见1.4中的系统提示)

1.2.On developer.apple.com in the Provisioning Portal, Select the App Id that you want to enable Push Notification, and click the ‘Config’ button.
1.2.在developer.apple.com的Provisioning Portal中,选择要发送推送通知的App Id,点击“Config”按钮

1.3.Check the Enable Push Notification Check box
1.3.勾上Enable Push Notification多选框

1.4.Click the ‘Config’ button for develop, and there is a guide for ‘How to request a certificate from KeyChain Assistant’. When you’ve done, click the ‘Continue’.
1.4.点击开发对应的’Config’,然后回出来一个向导告诉你如何生成CSR文件

1.5.Select the CSR file that generated by last step, then click ‘Generate’. (In this step, DO NOT use the Safari, or the ‘generate’ button will not response to your click at all……)
1.5.在最后一步,选择生成的CSR文件,然后点击‘Generate’。(坑爹的就是Safari下这个按钮点了没有任何效果,换别的浏览器就好了,汗···)

1.6.Download the generated certificate and install on your server.(On mac, just double click the certificate)
1.6.下载生成的证书并且双击它进行安装

1.7.Do the same for Production, following step 1.4,1.5,1.6.
1.7.对于发布版本,按照1.4, 1.5 和1.6的步骤再来一次。

2.Build the .pem file for our server to connect to APNS.
2.生成用来从服务器连接APNS的PEM文件

2.1.Copy the .p12, .csr, .cer files together in one place.
2.1.将前面得到的.p12, .csr, .cer文件放在一起。这时一共有6个文件,对应Develop,比如叫做dev.p12,dev.csr,dev.cer;对于发布有另外三个文件,这里以dev为例

2.2.Convert the dev.cer into devCer.pem. In the terminal, run

openssl x509 -in dev.cer -inform der -out devCer.pem

2.2.把dev.cer转换成devCer.pem。打开终端,运行

openssl x509 -in dev.cer -inform der -out devCer.pem

2.3.Conver the dev.p12 into devKey.pem. In the terminal, run openssl pkcs12 -nocerts -out devKey.pem -in dev.p12. First you will be asked to input the password for the dev.p12 file, and then will let you input your password for devKey.pem file.
2.3.把dev.p12转换成devKey.pem. 在终端中运行 openssl pkcs12 -nocerts -out devKey.pem -in dev.p12。中间会让你首先输入.p12文件的密码,然后让你输入密码来保护生成的.pem文件

2.4.Combine the two pem file together. In the terminal, run

cat devCer.pem devKey.pem > dev.pem

2.4.把两个pem文件合成一个。运行

cat devCer.pem devKey.pem > dev.pem

2.5.Then we can test if things goes well. By run

telnet gateway.sandbox.push.apple.com 2195

to see if you can reach the APNS. Then run

openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert devCer.pem -key devKey.pem

to see if the two pem files are ok.
2.5.然后我们可以测试一下是否一切都正常。先运行

telnet gateway.sandbox.push.apple.com 2195

确定可以连接到APNS,然后运行

openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert devCer.pem -key devKey.pem

看看pem文件是不是ok的。

3.Setup the application project in xCode.
3.在xCode中配置应用程序

3.1.Open the application project in xCode, and code sign with the specific (the exact same bundle id) provisioning file. If you want debug the push notification in xCode, be sure the right develop provisioning file is used.
3.1.在code sign部分,选择正确的provisioning file

3.2.Add some code to enable push notification in your application as:
3.2.在app delegate中添加以下代码:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
    //Some other code here ... for the window or something.
    return YES;
}
#pragma mark notification
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{
    NSLog(@"Failed to Get Token, Error: %@", error);
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
    NSLog(@"Success Get Token : %@", deviceToken);
}

3.3.Run your application in the real device, not simulator(the simulator is not support the push notification)
3.3.在真机上运行应用程序(模拟器是不支持推送的,也无法测试)

3.4.If you get the log of “Failed to Get Token”, then you must have something wrong in the previous steps.
3.4.如果发现输出了”Failed to Get Token”,说明前面步骤上有问题。

3.5.Else you will get a log like : “Success Get Token : <90757852 {6 segment of this kind of hex numbers} 82728ad7>“, record this deviceToken, which will be used for testing.
3.5.正常情况下,你可以获得一条消息”Success Get Token : <90757852 {6 segment of this kind of hex numbers} 82728ad7>“,记录下这段deviceToken,后面的测试会用到它

3.6.On your device, there will be an alert to ask permission for push notification, tap on ‘OK’
3.6.在第一次运行的时候,应该会有系统的alert让你允许推送通知,点’OK’就行。

4.Test the Push Notification For Development
4.然后就可以测试一下推送了。

4.1.paste the following code in to testPush.php file
4.1.把下面这段代码保存为testPush.php文件

 $message,
    'sound' => 'default'
    );

// Encode the payload as JSON
$payload = json_encode($body);

// Build the binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;

// Send it to the server
$result = fwrite($fp, $msg, strlen($msg));

if (!$result)
    echo 'Message not delivered' . PHP_EOL;
else
    echo 'Message successfully delivered' . PHP_EOL;

// Close the connection to the server
fclose($fp);

4.2.Modify the variables at the first few lines according to your situation. The deviceToken will be used here.
4.2.修改文件最开始的几个变量。这里会用到你刚才记录下的deviceToken。

4.3.Running the php code.
4.3.运行一下这段php代码。

php testPush.php

Reference:
http://www.raywenderlich.com/3443/apple-push-notification-services-tutorial-part-12
http://article.ityran.com/archives/194
http://www.cocoachina.com/applenews/devnews/2012/1212/5312.html

【转】iOS开发中的UITableView编辑模式

文章写得很好,转载自:http://my.oschina.net/plumsoft/blog/53271

这篇文章主要讲的表格的操作包括:标记行、移动行、删除行、插入行。

这次就不从头建立工程了,在http://www.oschina.net/code/snippet_164134_9876下载工程。这个工程就是最简单的产生一个表格并向其中写入数据。用Xcode 4.2打开它,在这个工程基础上实现以上操作。

1、标记行

这里讲的标记行指的是单击此行,可以实现在此行右边出现一个勾,如下图所示:

为了实现标记功能,在ViewController.m中@end之前添加代码:

#pragma mark -
#pragma mark Table Delegate Methods
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 
    UITableViewCell *oneCell = [tableView cellForRowAtIndexPath: indexPath];
    if (oneCell.accessoryType == UITableViewCellAccessoryNone) {
        oneCell.accessoryType = UITableViewCellAccessoryCheckmark;
    } else 
        oneCell.accessoryType = UITableViewCellAccessoryNone;
    [tableView deselectRowAtIndexPath:indexPath animated:YES]; 
}

该代码实现:单击某行时,若此行未被标记,则标记此行;若此行已经被标记,则取消标记。

运行效果如上图。

上面的代码实际上就是修改某行的accessoryType属性,这个属性可以设为四个常量:

UITableViewCellAccessoryCheckmark
UITableViewCellAccessoryDetailDisclosureButton
UITableViewCellAccessoryDisclosureIndicator
UITableViewCellAccessoryNone

效果依次如下图所示:

            

   UITableViewCellAccessoryCheckmark            UITableViewCellAccessoryDetailDisclosureButton

                

UITableViewCellAccessoryDisclosureIndicator                   UITableViewCellAccessoryNone

注意,上面第二张图片中的蓝色圆圈不仅仅是一个图标,还是一个控件,点击它可以触发事件,在上一篇博客《iOS开发16:使用Navigation Controller切换视图》使用过。

2、移动行

想要实现移动或者删除行这样的操作,需要启动表格的编辑模式。使用的是setEditing:animated:方法。

2.1 打开ViewController.xib,将其中的表格控件映射成Outlet到ViewController.h,名称为myTableView。

2.2 打开ViewController.m,在viewDidLoad方法最后添加代码:

//启动表格的编辑模式
[self.myTableView setEditing:YES animated:YES];

2.3 在@end之前添加代码:

//打开编辑模式后,默认情况下每行左边会出现红的删除按钮,这个方法就是关闭这些按钮的
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView
           editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath { 
    return UITableViewCellEditingStyleNone; 
} 

//这个方法用来告诉表格 这一行是否可以移动
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { 
    return YES; 
}

//这个方法就是执行移动操作的
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)
        sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
    NSUInteger fromRow = [sourceIndexPath row]; 
    NSUInteger toRow = [destinationIndexPath row]; 
    
    id object = [list objectAtIndex:fromRow]; 
    [list removeObjectAtIndex:fromRow]; 
    [list insertObject:object atIndex:toRow]; 
}

editingStyleForRowAtIndexPath这个方法中用到了常量UITableViewCellEditingStyleNone,它表示不可编辑,这里的编辑指的是删除和插入。表示表格行的编辑模式的常量有:

UITableViewCellEditingStyleDelete
UITableViewCellEditingStyleInsert
UITableViewCellEditingStyleNone

顾名思义,第一个表示删除,第二个表示插入,第三个表示不可编辑。

若将editingStyleForRowAtIndexPath方法中的UITableViewCellEditingStyleNone依次换成上面三个值,则它们运行的效果依次如下图所示:

     

2.4 运行,从下图可以看到实现了行的移动:

但是也会发现,现在无法对每行进行标记了。这说明,在编辑模式下,无法选择行,从而didSelectRowAtIndexPath这个方法不会执行。

3、删除行

从第2步过来,实现删除某行,其实比较简单了。

3.1将editingStyleForRowAtIndexPath方法中的UITableViewCellEditingStyleNone修改成UITableViewCellEditingStyleDelete。

3.2 在@end之前添加代码:

//这个方法根据参数editingStyle是UITableViewCellEditingStyleDelete
//还是UITableViewCellEditingStyleDelete执行删除或者插入
- (void)tableView:(UITableView *)tableView commitEditingStyle:
    (UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    NSUInteger row = [indexPath row];
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        [self.list removeObjectAtIndex:row]; 
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                         withRowAnimation:UITableViewRowAnimationAutomatic]; 
    }
}

在这个方法中又出现了一个常量:UITableViewRowAnimationAutomatic,它表示删除时的效果,类似的常量还有:

UITableViewRowAnimationAutomatic
UITableViewRowAnimationTop
UITableViewRowAnimationBottom
UITableViewRowAnimationLeft
UITableViewRowAnimationRight
UITableViewRowAnimationMiddle
UITableViewRowAnimationFade
UITableViewRowAnimationNone

它们的效果就不一一介绍了,可以在实际使用时试试。

3.3 运行,看看效果:

     

刚运行时显示如左边的图片,点击某一行左边的圆圈图标,会显示如中间图片所示。然后点击Delegate按钮,那一行就会被删除掉,如右边的那张图片所示,它显示的是删除时的效果。

4、插入行

这个与删除行类似。

4.1 首先将editingStyleForRowAtIndexPath方法中的UITableViewCellEditingStyleDelete修改成UITableViewCellEditingStyleInsert。

4.2在3.2添加的方法中添加代码:

else {
    //我们实现的是在所选行的位置插入一行,因此直接使用了参数indexPath
    NSArray *insertIndexPaths = [NSArray arrayWithObjects:indexPath,nil];
    //同样,将数据加到list中,用的row
    [self.list insertObject:@"新添加的行" atIndex:row];
    [tableView insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationRight];
}

上面的代码中也可以不用insertRowsAtIndexPaths方法,而直接使用[tableView reloadData];语句,但是这样就没有添加的效果了。

4.3 好了,运行一下:

     

刚运行时如上面左图所示,单击了某个加号后,新的一行就从右边飞进来了,因为在insertRowsAtIndexPaths中用了参数UITableViewRowAnimationRight。

 

ARC – Automatic Reference Counting in iOS Development

ARC帮我们做了很多事情,主要的几点如下:

1·自动生成dealloc函数,帮我们释放对象中的变量
2·如果你要自己写dealloc,它会帮你加上[super dealloc];
3·AutoreleasePool用@autoreleasepool{}的block代替
4·weak修饰符,在所指对象被释放后自动置为nil,cool!



参考(Ref.)
https://developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html

Why we use ‘copy’ attribute for NSString property?

@interface AClass:NSObjet
@property (nonatomic, copy) NSString* aStrProperty;
@end

Like the code above, we use ‘copy’ instead of ‘retain’ attribute in the NSString property. For the reason, is that we do not want the original NSString object to be modified in this class.
像上面这段代码,为什么要用copy而不是retain呢?因为我们不希望外面的字符串在不经意间由这个类的对象修改。

But for that a NSString cannot be modified, why not using the ‘retain’ instead of ‘copy’? Because, one can also assign the aStrProperty with a NSMutableString instead of NSString. Thus, ‘copy’ is more safe than ‘retain’.
可是,既然NSString是不可以被修改的,为什么还有这个担忧呢?因为虽然NSString不可修改,可是使用者完全可能将一个NSMutableString传递给aStrProperty,然后在类方法里修改它的内容,这不是我们希望出现的,所以采用copy。

Access to ‘class’ Tag Attribute in HTML using HtmlDocumentElement in C#

<p class="aClass">some content</p>

像上面这一段html代码,在用HtmlDocumentElement进行处理的时候,用直观的

element.getAttribute("class");

是得不到class属性的值”aClass”的,原因是IE用className代替了class。

所以要想得到class属性,需要这么做:

element.getAttribute("className");

参考:http://zhidao.baidu.com/question/208025778.html

Size with UITextView in iOS Development

In the iOS development, the UITextView is frequently used for display a NSString with multiple lines.
(在iOS开发中,经常用UITextView来显示一段多行的NSString)

In some of the applications, we need place a UITextView in UITableViewCell.
(在有些时候,会在UITableCell中使用它)

In the UITableViewCell, the height of cell is determined according to the height of UITextView, and the height of UITextView is dependent to the size of NSString which is displaying.
(然后如果要根据字符串绘制之后所占的高度来动态调整UITableViewCell的高度的话,就需要去计算字符串所占大小,再用这个大小去计算UITextView所占大小,再进一步计算Cell的高度)

When we calculated the size of NSString with the methods -sizeWithFont…blablabla
(用NSString自带的-sizeWithFont….系列函数可以计算出字符串的绘制所占用的区域大小)

It’s just the size of text.
(但是这只是文本本身的大小)

Outside the text, there is some space edge within the UITextView, and the edge is 8px in the top and bottom direction, 11px in the left and right direction.
(UITextView还有一个Padding边框,这个边框的大小是top和bottom是8px,left和right是11px)

So, we can get the height of text first, and then add 16px to get the height of UITextView, and then calculate the height of the UITableViewCell.
(所以,我们可以先计算出文本的高度,然后加上16px得到UITextView的高度,再去计算Cell的高度)

Service in Android Development

记录一下,这篇文章写得很好,很简洁,以至于我都没动力复述一遍了:
http://www.cnblogs.com/trinea/archive/2012/11/08/2699856.html

这篇文章中描述了如何创建Service,startService和bindService的区别(后者可以和Activity通讯,其实前者也行)。
针对bindService,在Service中创建一个Binder,里面可以自定义Service提供给外界的接口,在Activity调用bindService之后,在成功连接到Service的回调里面,Service提供的Binder会作为参数传给Activity。

这样,Activity就可以随心所欲操作Service了。

不过这篇文章没有回答的一个问题是:如果Service中的一些事件需要通知Activity怎么办?
这个问题我摸索了一段时间,用了好些方法来做。



第一,创建一个叫做ServiceListener的抽象类,里面定义好Service要通知Activity的函数。然后当Activity绑定到Service的时候,在Binder中提供一个注册Listener的方法(当然unregister也提供)。这样Activity可以创建一个Listener的子类来针对感兴趣的部分进行操作;而Service这边维护一个ArrayList数组,每次事件一到就通知所有的listener。

这个方法可行,不过有一个问题是,这些回调函数不一定是在主线程被调用的(因为Service经常在辅助线程干活儿)。



第二,还是沿用上面的结构,不过把Listener改为Handler,在Service这边定义好各种事件定义的Message,然后当事件发生的时候,直接向所有的Handler发送Message。由于Activity中创建的Handler都是主线程上,所以可以直接干UI的活儿。

这个方法也不错,不过损失了上一个方法中定义好的接口,没有那么方便了,开发的时候,还需要去查查Service怎么定义的各种Message,不是很方便。



第三,综合上面两种。Service还是定义一个Listener,只不过它继承自Handler,并且定义好需要通知Activity的各种接口。然后在这个基类里面,进行handleMessage()。针对每一种Message去调用对应的接口。然后Activity这边创建一个Listener的子类,重载这些接口就能干活儿了。一举两得。



—————-我是跨进程的分割线——————
不过呢,这种做法只能用于同在一个进程内的Service和Activity之间的通讯,如果Activity和Service不在一个进程的话,那就只能借助于AIDL(Android Interface Description Language)了。

在初步研究了AIDL之后,从Activity控制Service似乎是没有什么问题的(代码以后补上)。

但是AIDL并不能传送复杂数据类型,像上面方法三的办法就不能了,虽然可以在Service那边的接口中提供registerListener和unregisterListener方法,但是不能直接传送一个Handler的子类,那怎么办呢?

接着深入研究AIDL,发现虽然不能传送一个复杂数据,但是interface是可以传送的。因此我们再定义一个接口叫做IServiceListener,里面提供以简单数据作为参数的各种操作,这些操作是Service希望通知Listener的。然后在方法三的Listener中,实现这个IServiceListener的Stub类,里面针对各种调用分别向自己(Listener本身是Handler)sendMessage。而且提供一个getStubForRegister()方法返回这个Stub类就好了。这样在IService中的registerListener和unregisterListener都以这个IServiceListener为参数即可。

这样就实现了一个终极方案,不论Service在哪个进程,只需要在Activity所在进程创建一个Listener,然后重载其中的钩子函数,在Bind到Service的时候,向Service注册Listener.getStub()就可以了。Service一旦有消息要通知Listener,就会在Listener所在的线程中(一般是主线程),调用对应的钩子函数,这样就完美了。



—————-我是BUG的分割线——————
今天(20130507)遇到一个问题,bindService总返回false,也就说没有bind成功,各种测试之后发现,额,Manifest.xml中没有声明这个Service。
怎么声明呢?那就是在和activity标签并列的地方插入一段:

<service android:name="com.xxx.xxx.xxxService" />

ListView in Android Develop

ListView是比较常用的控件,相当于iOS中的TableView,用来展示数据列表。

使用方法的话也很简单:第一定义每一个Cell的布局,第二实例化一个SimpleAdapter,第三将这个Adapter绑定到ListView。



一、定义Cell布局:
这个相当于在iOS中新建一个Cell的nib或者如果愿意的话,写代码也行。
比如定义一个Layout XML文件如下(文件名是”list_items.xml”,这个很重要,后面会用到这个名字)

<?xml version="1.0" encoding="utf-8"?>  
<RelativeLayout   
    android:id="@+id/RelativeLayout01"   
    android:layout_width="fill_parent"   
    xmlns:android="http://schemas.android.com/apk/res/android"   
    android:layout_height="wrap_content"   
    android:paddingBottom="4dip"   
    android:paddingLeft="12dip"  
    android:paddingRight="12dip">  
<ImageView   
    android:paddingTop="12dip"  
    android:layout_alignParentRight="true"  
    android:layout_width="wrap_content"   
    android:layout_height="wrap_content"   
    android:id="@+id/ItemImage"  
    />   
<TextView   
    android:text="TextView01"   
    android:layout_height="wrap_content"   
    android:textSize="20dip"   
    android:layout_width="fill_parent"   
    android:id="@+id/ItemTitle"  
    />  
<TextView   
    android:text="TextView02"   
    android:layout_height="wrap_content"   
    android:layout_width="fill_parent"   
    android:layout_below="@+id/ItemTitle"   
    android:id="@+id/ItemText"  
    />  
</RelativeLayout> 

有两个TextView和一个ImageView。



二、实例化一个SimpleAdapter
可以实现自己的数据源,只要实现了ListAdapter接口就行。Android给出了一个方便的Adapter:SimpleAdapter,只要给它数据源和数据源每一项到布局中控件id的映射,它就会给ListView提供每一项的数据和对应的映射,很方便。

//生成动态数组,加入数据  
        ArrayList<HashMap<String, Object>> listItem = new ArrayList<HashMap<String, Object>>();  
        for(int i=0;i<10;i++)  
        {  
            //每一项是一个数据源,相当于是Key-Value。这个例子里面有三项数据,第一是图片,后两个是文本
            HashMap<String, Object> map = new HashMap<String, Object>();  
            map.put("ItemImage", R.drawable.checked);//图像资源的ID  
            map.put("ItemTitle", "Level "+i);  
            map.put("ItemText", "Finished in 1 Min 54 Secs, 70 Moves! ");  
            listItem.add(map);  
        }  
        //生成适配器的Item和动态数组对应的元素  
        SimpleAdapter listItemAdapter = new SimpleAdapter(this,listItem,//数据源   
            R.layout.list_items,//ListItem的XML实现  
            //动态数组与ImageItem对应的子项,这是和上面每一项数据中对应的Key
            new String[] {"ItemImage","ItemTitle", "ItemText"},   
            //ImageItem的XML文件里面的一个ImageView,两个TextView ID
            //这里是针对上面每一项的Key在我们定义的Cell布局中的控件id
            new int[] {R.id.ItemImage,R.id.ItemTitle,R.id.ItemText}  
        ); 

初始化SimpleAdapter的最后两个参数为每一项数据中的内容指定了在Cell中的显示控件。这里比较有意思的是,针对不同的控件,会自动去完成内容的设置,比如textview是setText(aValue),imageview是setImage(aImage)。



三、绑定adapter到listview
接在上面的代码后面,两句话就可以了:

        ListView list = (ListView) findViewById(R.id.ListView01);  
        list.setAdapter(listItemAdapter);

这样,就能显示出需要的数据了。



四、动态删减数据条目
保留住开始数据源的那个listItem,直接对它进行修改,之后调用adapter的notifyDataChanged

listItem.add(message.getHashMap());
ListView lv = (ListView)findViewById(R.id.listViewForCustomMessages);
((SimpleAdapter)lv.getAdapter()).notifyDataSetChanged();



参考
http://www.iteye.com/topic/540423,上面的例子来自这里,写的很简洁,文章中还有事件处理的代码。

Handler in Android Development

Handler是在Android系统中用来做消息分发和处理的类。在涉及到跨线程调用的时候,可以使用这个组件。
Handler is used for message dispatch and process. It’s useful to dealing with inter-thread communication.

每一个Handler绑定在一个Looper上,Looper可以理解为一个线程中的消息循环,上面有一个消息队列MessageQueue。Looper每次从消息队列取一个消息Message,然后让Handler去处理,然后再去取一个消息,继续处理这样子。
Each handler is attached to a Looper. Looper can be seen as a message loop in a thread, and in the thread, there is a MessageQueue. Looper will pick a message from the queue, and let the handler to handle the message, and then pick next message, let handler to process, ….., and so on.

系统会为每一个Activity自动创建一个Looper进行消息循环的处理。如果是自己创建的线程,默认是没有Looper的,可以通过Looper.prepare()和Looper.loop()来给调用线程加上一个消息循环。
System will create an Looper for Activity automatically. And if you create your own Thread, by default there is no Looper on it. But you can call Looper.prepare() and Looper.loop() in the thread to initialize an looper for it. See the code below:



给自定义线程添加消息循环
Add a looper to a thread

class LooperThread extends Thread {
      public Handler mHandler;

      public void run() {
          //Initialize the current thread as a looper. 
          //This gives you a chance to create handlers that then reference this looper, before actually starting the loop. 
          //Be sure to call loop() after calling this method, and end it by calling quit().
          Looper.prepare();

          //the handler will attach to the thread in which it was created.
          mHandler = new Handler() {
              public void handleMessage(Message msg) {
                  // process incoming messages here
              }
          };

          //Run the message queue in this thread. Be sure to call quit() to end the loop.
          Looper.loop();
      }
  }



一个用Handler来进行UI更新的例子
An example to use handler update UI

From:http://www.pin5i.com/showtopic-android-handler.html

public class MyHandlerActivity extends Activity {
    Button button;
    MyHandler myHandler;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.handlertest);

        button = (Button) findViewById(R.id.button);
        myHandler = new MyHandler();
        // 当创建一个新的Handler实例时, 它会绑定到当前线程和消息的队列中,开始分发数据
        // Handler有两个作用, (1) : 定时执行Message和Runnalbe 对象
        // (2): 让一个动作,在不同的线程中执行.

        // 它安排消息,用以下方法
        // post(Runnable)
        // postAtTime(Runnable,long)
        // postDelayed(Runnable,long)
        // sendEmptyMessage(int)
        // sendMessage(Message);
        // sendMessageAtTime(Message,long)
        // sendMessageDelayed(Message,long)
       
        // 以上方法以 post开头的允许你处理Runnable对象
        //sendMessage()允许你处理Message对象(Message里可以包含数据,)

        MyThread m = new MyThread();
        new Thread(m).start();
    }

    /**
     * 接受消息,处理消息 ,此Handler会与当前主线程一块运行
     * */

    class MyHandler extends Handler {
        public MyHandler() {
        }

        public MyHandler(Looper L) {
            super(L);
        }

        // 子类必须重写此方法,接受数据
        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            Log.d("MyHandler", "handleMessage......");
            super.handleMessage(msg);
            // 此处可以更新UI
            Bundle b = msg.getData();
            String color = b.getString("color");
            MyHandlerActivity.this.button.append(color);

        }
    }

    class MyThread implements Runnable {
        public void run() {

            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            Log.d("thread.......", "mThread........");
            Message msg = new Message();
            Bundle b = new Bundle();// 存放数据
            b.putString("color", "我的");
            msg.setData(b);

            MyHandlerActivity.this.myHandler.sendMessage(msg); // 向Handler发送消息,更新UI

        }
    }

}



补充一点,同一个Message不能发给两个Handler,那样会报错:AndroidRuntimeException:This message is already in use。如果要广播消息,可以这么做:

// clone a message from the message want to broadcast
Message cloneMessage = Message.obtain(originalMessage);
// send the cloned message to other handlers
anotherHandler.postMessage(cloneMessage);
// send the original message to the handler where it should be posted.
originalHandler.postMessage(originalMessage);



参考 | Reference
http://developer.android.com/intl/zh-CN/reference/android/os/Handler.html
http://developer.android.com/intl/zh-CN/reference/android/os/Looper.html
http://www.pin5i.com/showtopic-android-handler.html

【转】iOS中的一些宏定义,用于进行log输出定位Bug。

转自:http://www.linuxidc.com/Linux/2012-12/76754.htm

我该如何在日志输出信息中添加上下文信息,例如当前方法或者行号。

C预处理器提供了一些标准宏,可以提供当前文件,行号,或者函数的信息。另外,Objective-C有_cmd隐式参数,可以提供当前函数的选择器,以及将选择器和类转换为字符串的功能。你可以在调试或者错误处理时在NSLog语句中提供这些上下文信息。

下面是打印当前方法和行号的例子。

NSMutableArray *someObject = [NSMutableArray array];
NSLog(@"%s:%d someObject=%@", __func__, __LINE__, someObject);
[someObject addObject:@"foo"];
NSLog(@"%s:%d someObject=%@", __func__, __LINE__, someObject);

下面是在日志语句中很有用的非常常见的宏和表达式。

C/C++/Objective-C中用于日志输出的预处理宏.

Macro Format Specifier Description
__func__ %s 当前函数前面
__LINE__ %d 源码文件中的行号
__FILE__ %s 源码文件完整路径
__PRETTY_FUNCTION__ %s 和__func__类似, 但是在 C++ 代码中包含更多的信息.

Objective-C中用于日志输出的表达式

Expression Format Specifier Description
NSStringFromSelector(_cmd) %@ 当前选择器的名字
NSStringFromClass([self class]) %@ 当前对象类的名字
[[NSString stringWithUTF8String:__FILE__] lastPathComponent] %@ 源码文件的名称
[NSThread callStackSymbols] %@  

当前栈信息的刻度字符串数组。仅用于调试,不用向终端用户展示或者在代码中用作任何逻辑。

 

被路由器断开VPN连接

换了一个路由器之后,VPN就工作不正常了,连接vpn之后1、2秒,就报错说:“被通讯设备断开连接”

这让我怎么翻墙啊。。

反复测试,定位问题就是路由器,但是这个路由器应该是好的啊,估计是设置里面的问题。然后就枚举所有设置,终于让我发现了问题出在MTU上。

路由器默认设置是1436,将它改成1492,就再也不会出现断开连接的问题了。

KVO in iOS Development

继续挖坑

这篇文章还不错:Objective-C KVO 编程 改善现有iOS代码设计
———– 下面是这篇文章的内容,仅作为backup ———-

KVC很多人都知道,那么什么是KVO呢?Key Value Observing,直译为:基于键值的观察者。
KVO的优点
当有属性改变,KVO会提供自动的消息通知。这样的架构有很多好处。首先,开发人员不需要自己去实现这样的方案:每次属性改变了就发送消息通知。
这 是KVO机制提供的最大的优点。因为这个方案已经被明确定义,获得框架级支持,可以方便地采用。开发人员不需要添加任何代码,不需要设计自己的观察者模 型,直接可以在工程里使用。其次,KVO的架构非常的强大,可以很容易的支持多个观察者观察同一个属性,以及相关的值。

主要用于有关视图界面交互编程中,比如,实体(或者叫名词、或者叫域模型),在应用中表示名词的部分,类似Java中的Java Bean。再具体点儿,在下文的示例中。
图书(Book类),就是个实体。它的属性有书名(name)和价格(price)。那么,在界面开发中,可能有多个视图和这个实体有关联。
如果等实体(Book)的价格(price)发生了变化,这些关联的界面都要被修改。

比较好的做法是使用观察者模式,各个界面都注册观察者,观察图书的价格变化,当变化后改动自己的视图。

ObjC中提供了这个模式的解决方案,就是KVO。以下用简单示例说明KVO的实现方式。

Book类,头文件:

#import 

@interface Book : NSObject { 
    NSString *name; 
    float price; 
}

@end

 

Book类的实现文件,没做任何事情,不贴了。

现在,假设我有个视图,MyView,我这里为了不带入实际视图类的复杂性,只是模拟一个。用普通类。头文件:

#import 

@class Book;

@interface MyView : NSObject { 
    Book *book; 
}

- (id) init:(Book *)theBook;

@end

 

实现文件:

#import "MyView.h"

@implementation MyView

- (id) init:(Book *)theBook { 
    if(self=[super init]){ 
        book=theBook; 
        [book addObserver:self forKeyPath:@"price" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil]; 
    } 
    return self; 
}

- (void) dealloc{ 
    [book removeObserver:self forKeyPath:@"price"]; 
    [super dealloc]; 
}

- (void)observeValueForKeyPath:(NSString *)keyPath 
                      ofObject:(id)object 
                        change:(NSDictionary *)change 
                       context:(void *)context{ 
    if([keyPath isEqual:@"price"]){ 
        NSLog(@">>>>>>>price is changed"); 
        NSLog(@"old price is %@",[change objectForKey:@"old"]); 
        NSLog(@"new price is %@",[change objectForKey:@"new"]);
    } 
}

@end

 

这里的init方法中,可以看到向book实例增加了观察者,是针对价格price属性的。这里用的:

options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew

可以让通知携带旧的price值和新的price值。后面会看到。observeValueForKeyPath方法,就是当price属性发生变化后,调用的方法。

main方法中调用的代码:

Book *book4=[[Book alloc] init]; 
NSArray *bookProperties=[NSArray arrayWithObjects:@"name",@"price",nil]; 
NSDictionary *bookPropertiesDictionary=[book4 dictionaryWithValuesForKeys:bookProperties]; 
NSLog(@"book values: %@",bookPropertiesDictionary);

[[[MyView alloc] init:book4] autorelease];

NSDictionary *newBookPropertiesDictionary=[NSDictionary dictionaryWithObjectsAndKeys:@"《Objective C入门》",@"name", 
                                           @"20.5",@"price",nil]; 
[book4 setValuesForKeysWithDictionary:newBookPropertiesDictionary]; 
NSLog(@"book with new values: %@",[book4 dictionaryWithValuesForKeys:bookProperties]);

 

在这里引发了price属性变化,触发了MyView的处理。

另外,要注意,在Book实例释放前,要删除观察者,否则会报错,这里是在MyView里面实现的:

- (void) dealloc{ 
    [book removeObserver:self forKeyPath:@"price"]; 
    [super dealloc]; 
}

 

这里假定MyView实例的生命周期小于等于Book实例。实际使用可能要根据情况在合适的地方addObserver和removeObserver。


KVC in iOS Development

原来objective-c里面有这么强大的东西,以前只是用过,没有深入了解。
转载一个,挖个坑,以后慢慢填。

 

1.    基本概念

MODEL

主要是英文文档里面经常出现的一些概念,讲解一下,方便英文文档的阅读。

IOS应用开发是遵循MVC设计模式的,Cocoa框架用Object Modeling的规则来规范一个Model的实现。

ObjectModeling有如下几个概念的规定:

Entity:表示持有数据的一个实体

Property实体中的成员,分为Attribute和:Relationship

Attribute:基本类型的成员,比如:数字、NSString。

Relationship:指向其它Entity的关系型成员,它又有to 1Relationship和to manyRelationship的区别。

AccessorMethod:getter,setter。

举例:

如下是一个部门和员工关系的Model

部门:Department

部门名称(NSString) 成员(NSArray) 部长(Employee)
MIC (所有成员) 老王(一个成员)
MIB    

员工:Employee

名字(NSStirng) 所属部门(Department)
小王 MIC
   

 

使用KVC、KVO的优势

通过规定了一组通用的Cocoa命名法则、调用规则等,实现了如下功能:

²  使用一对高度规范化的访问方法,获取以及设置任何对象的任何属性的值。

²  通过继承一个特定的方法,并且指定希望监视的对象及希望监视的属性名称,就能在该对象的指定属性的值发生改变时,得到一个“通知”(尽管这不是一个真正意 义上的通知),并且得到相关属性的值的变化(原先的值和改变后的新值)。

²  通过一个简单的函数调用,使一个视图对象的一个指定属性随时随地都和一个控制器对象或模型对象的一个指定属性保持同步。

2.    KVC

2.1  概述

KVC是KeyValue Coding的简称,它是一种可以直接通过字符串的名字(key)来访问类属性的机制。而不是通过调用Setter、Getter方法访问。

当使用KVO、Core Data、CocoaBindings、AppleScript(Mac支持)时,KVC是关键技术。

 

2.2  如何使用KVC

关键方法定义在:NSKeyValueCodingprotocol

KVC支持类对象和内建基本数据类型。

 

2.2.1         获取值

valueForKey:,传入NSString属性的名字。

valueForKeyPath:,传入NSString属性的路径,xx.xx形式。

valueForUndefinedKey它的默认实现是抛出异常,可以重写这个函数做错误处理。

2.2.2         修改值

setValue:forKey:

setValue:forKeyPath:

setValue:forUndefinedKey:

setNilValueForKey: 当对非类对象属性设置nil时,调用,默认抛出异常。

2.2.3         一对多关系成员的情况

mutableArrayValueForKey:有序一对多关系成员  NSArray

mutableSetValueForKey:无序一对多关系成员  NSSet

 

示例:

 

2.3  KVC的实现细节

搜索Setter、Getter方法

这一部分比较重要,能让你了解到KVC调用之后,到底是怎样获取和设置类成员值的。

2.3.1         搜索简单的成员

如:基本类型成员,单个对象类型成员:NSInteger,NSString*成员。

a. setValue:forKey的搜索方式:

  1. 首先搜索set<Key>:方法

如果成员用@property,@synthsize处理,因为@synthsize告诉编译器自动生成set<Key>:格式的setter方法,所以这种情况下会直接搜索到。

注意:这里的<Key>是指成员名,而且首字母大写。下同。

  1. 上面的setter方法没有找到,如果类方法accessInstanceVariablesDirectly返回YES(注:这是NSKeyValueCodingCatogery中实现的类方法,默认实现为返回YES)。

那么按_<key>,_is<Key>,<key>,is<key>的顺序搜索成员名。

  1. 如果找到设置成员的值,如果没有调用setValue:forUndefinedKey:。

 

b. valueForKey:的搜索方式:

  1. 首先按get<Key>、<key>、is<Key>的顺序查找getter方法,找到直接调用。如果是bool、int等内建值类型,会做NSNumber的转换。

  2. 上面的getter没有找到,查找countOf<Key>、objectIn<Key>AtIndex:、<Key>AtIndexes格式的方法。

如果countOf<Key>和另外两个方法中的一个找到,那么就会返回一个可以响应NSArray所有方法的代理集合(collection proxy object)。发送给这个代理集合(collection proxy object)的NSArray消息方法,就会以countOf<Key>、objectIn<Key>AtIndex:、<Key>AtIndexes这几个方法组合的形式调用。还有一个可选的get<Key>:range:方法。

  1. 还没查到,那么查找countOf<Key>、enumeratorOf<Key>、memberOf<Key>:格式的方法。

如果这三个方法都找到,那么就返回一个可以响应NSSet所有方法的代理集合(collection proxy object)。发送给这个代理集合(collection proxy object)的NSSet消息方法,就会以countOf<Key>、enumeratorOf<Key>、memberOf<Key>:组合的形式调用。

  1. 还是没查到,那么如果类方法accessInstanceVariablesDirectly返回YES,那么按_<key>,_is<Key>,<key>,is<key>的顺序直接搜索成员名。

  2. 再没查到,调用valueForUndefinedKey:。

 

2.3.2         查找有序集合成员,比如NSMutableArray

mutableArrayValueForKey:搜索方式如下:

  1. 搜索insertObject:in<Key>AtIndex:、removeObjectFrom<Key>AtIndex:或者insert<Key>:atIndexes、remove<Key>AtIndexes:格式的方法。

如果至少一个insert方法和至少一个remove方法找到,那么同样返回一个可以响应NSMutableArray所有方法的代理集合。那么发送给这个代理集合的NSMutableArray消息方法,以insertObject:in<Key>AtIndex:、removeObjectFrom<Key>AtIndex:、insert<Key>:atIndexes、remove<Key>AtIndexes:组合的形式调用。还有两个可选实现的接口:replaceObjectIn<Key>AtIndex:withObject:、replace<Key>AtIndexes:with<Key>:。

  1. 否则,搜索set<Key>:格式的方法,如果找到,那么发送给代理集合的NSMutableArray最终都会调用set<Key>:方法。

也就是说,mutableArrayValueForKey取出的代理集合修改后,用set<Key>:重新赋值回去。这样做效率会差很多,所以推荐实现上面的方法。

  1. 否则,那么如果类方法accessInstanceVariablesDirectly返回YES,那么按_<key>,<key>的顺序直接搜索成员名。如果找到,那么发送的NSMutableArray消息方法直接转交给这个成员处理。

  2. 再找不到,调用setValue:forUndefinedKey:。

 

2.3.3         搜索无序集合成员,如:NSSet。

mutableSetValueForKey:搜索方式如下:

  1. 搜索add<Key>Object:、remove<Key>Object:或者add<Key>:、remove<Key>:格式的方法,如果至少一个insert方法和至少一个remove方法找到,那么返回一个可以响应NSMutableSet所有方法的代理集合。那么发送给这个代理集合的NSMutableSet消息方法,以add<Key>Object:、remove<Key>Object:、add<Key>:、remove<Key>:组合的形式调用。还有两个可选实现的接口:intersect<Key>、set<Key>:。

  2. 如果reciever是ManagedObejct,那么就不会继续搜索了。

  3. 否则,搜索set<Key>:格式的方法,如果找到,那么发送给代理集合的NSMutableSet最终都会调用set<Key>:方法。也就是说,mutableSetValueForKey取出的代理集合修改后,用set<Key>:重新赋值回去。这样做效率会差很多,所以推荐实现上面的方法。

  4. 否则,那么如果类方法accessInstanceVariablesDirectly返回YES,那么按_<key>,<key>的顺序直接搜索成员名。如果找到,那么发送的NSMutableSet消息方法直接转交给这个成员处理。

  5. 再找不到,调用setValue:forUndefinedKey:。

 

KVC还提供了下面的功能

2.4  值的正确性核查

KVC提供属性值确认的API,它可以用来检查set的值是否正确、为不正确的值做一个替换值或者拒绝设置新值并返回错误原因。

实现核查方法

为如下格式:validate<Key>:error:

如:

 

  1. -(BOOL)validateName:(id *)ioValue error:(NSError **)outError
  2. {
  3.     // The name must not be nil, and must be at least two characters long.
  4.     if ((*ioValue == nil) || ([(NSString *)*ioValue length] < 2]) {
  5.         if (outError != NULL) {
  6.             NSString *errorString = NSLocalizedStringFromTable(
  7.                     @”A Person’s name must be at least two characters long”, @”Person”,
  8.                     @”validation: too short name error”);
  9.             NSDictionary *userInfoDict =
  10.                 [NSDictionary dictionaryWithObject:errorString
  11.                                             forKey:NSLocalizedDescriptionKey];
  12.             *outError = [[[NSError alloc] initWithDomain:PERSON_ERROR_DOMAIN
  13.                                                     code:PERSON_INVALID_NAME_CODE
  14.                                                 userInfo:userInfoDict] autorelease];
  15.         }
  16.         return NO;
  17.     }
  18.     return YES;
  19. }

 

调用核查方法:

validateValue:forKey:error:,默认实现会搜索 validate<Key>:error:格式的核查方法,找到则调用,未找到默认返回YES。

注意其中的内存管理问题。

 

2.5  集合操作

集合操作通过对valueForKeyPath:传递参数来使用,一定要用在集合(如:array)上,否则产生运行时刻错误。其格式如下:

 

Left keypath部分:需要操作对象路径。

Collectionoperator部分:通过@符号确定使用的集合操作。

Rightkey path部分:需要进行集合操作的属性。

2.5.1         数据操作

@avg:平均值

@count:总数

@max:最大

@min:最小

@sum:总数

确保操作的属性为数字类型,否则运行时刻错误。

2.5.2         对象操作

针对数组的情况

@distinctUnionOfObjects:返回指定属性去重后的值的数组

@unionOfObjects:返回指定属性的值的数组,不去重

属性的值不能为空,否则产生异常。

2.5.3         数组操作

针对数组的数组情况

@distinctUnionOfArrays:返回指定属性去重后的值的数组

@unionOfArrays:返回指定属性的值的数组,不去重

@distinctUnionOfSets:同上,只是返回值为NSSet

 

示例代码:

 

2.6  效率问题

相比直接访问KVC的效率会稍低一点,所以只有当你非常需要它提供的可扩展性时才使用它。

Toll Free Bridge in iOS Development

Toll Free Bridge is the channel connecting the Cocoa and CoreFoundation.
TFB是连接Cocoa和CoreFoundation的一个设计。
For example, we can use an Objc object of NSString as CFString, or reversed.
我们可以在程序中把NSString当做CFString来用,也可以把CFString当做NSString来用。
The detail is described in the article below.
下面这篇文章很详细得介绍了它。
http://www.winddisk.com/2012/08/16/toll-free-bridging/

Solve Discuz Forum Error 114: Table ‘forum_thread’ is marked as crashed and autorepair failed

Just now, I reboot the server, and after that the Discuz forum encounter an error 114 :
Table ‘forum_thread’ is marked as crashed and last (automatic) repair failed

It’s easy to solve this situation, just:

1.open the phpmyadmin
2.select the database that contain the forum
3.select the table forum_thread
4.in the sql tab, run “REPAIR TABLE ‘forum_thread'”
5.done!



Reference
http://www.acogle.cn/show_news.asp?id=473

Remove Push Notifications from Notification Center in iOS Development

If the notification is local, it’s easy by
如果是本地通知,下面的代码就解决了。

[[UIApplication sharedApplication] cancelAllLocalNotifications];

But if the notifications come from the push notification, this does’t work.
但是如果是来自于推送的话,这不管用。
After search and try, only the third method in a blog works, although it’s weird.
搜了很久发现有一个办法可以解决,虽然这个办法非常怪异。

UIApplication* application = [UIApplication sharedApplication];
NSArray* scheduledNotifications = [NSArray arrayWithArray:application.scheduledLocalNotifications];
application.scheduledLocalNotifications = scheduledNotifications;

<br>
Reference
http://josh-asch.net/2012/02/29/ios-development-remove-old-notifications-from-notification-center/

Macbook Pro Retina 黑屏

昨天开始,用着用着MBPR就黑了,然后各种折腾,按电源键,开合屏幕。之后有时候点按之后5-6s,会一闪大概2s又黑了(还是慢慢黑的),或者一亮之后就稳定不黑了。

今天写着代码,写着写着又黑了,而且怎么折腾都不亮,或者一亮又黑。随时受不了。打电话给苹果售后,然后售后说了一个方法,
1.到完全关机状态(如果不确定的话,就按着电源5s以上)
2.接上电源(后面操作估计不能断电)
3.按着左边的shift+control+option,和电源四个键5s以上,然后同时松开。这步之后电脑应该没有任何反应,还是处于关机状态。
4.在点一下电源键之后,迅速按住左边option+command和”r”,”p”,四个键不放,然后电脑会开始“咣咣咣”的响,4声之后同时松开。

也不知道管不管用,反正现在是好的。
其实是在售后问我序列号的时候,我把笔记本合上,反过来告诉他序列号,然后翻过来打开屏幕的时候,就好了。之后的操作也不知道是不是管用的。

================== 2013-1-30 更新 ===================
后来证明了3点:
1·问题依然存在
2·把笔记本翻过来一下再翻回去,问题都能解决。
3·客服人员说的方法没有用。

================== 2014-02-28 更新 ==================
终于找打了原因,其实就是MBPR以为合上了盖子,它的传感器不是传统的机械开关,而是磁性的。
前两天偶然的机会,我直接把本本放在自动麻将桌上,而且上面的铺了一层麻将(带磁性),然后放上去就黑了,拿起来就亮了。
所以总的说来,这不是问题,不过apple的客服应该知道这种可能性。